diff --git a/base/allocator/BUILD.gn b/base/allocator/BUILD.gn
index cffe6c2..4015196 100644
--- a/base/allocator/BUILD.gn
+++ b/base/allocator/BUILD.gn
@@ -216,18 +216,17 @@
       "$tcmalloc_dir/src",
     ]
 
-    configs -= [
-      "//build/config/compiler:chromium_code",
-
-      # Thumb mode disabled due to bug in clang integrated assembler
-      # TODO(https://llvm.org/bugs/show_bug.cgi?id=31058)
-      "//build/config/compiler:compiler_arm_thumb",
-    ]
+    configs -= [ "//build/config/compiler:chromium_code" ]
     configs += [
       "//build/config/compiler:no_chromium_code",
       ":tcmalloc_flags",
     ]
 
+    # Thumb mode disabled due to bug in clang integrated assembler
+    # TODO(https://llvm.org/bugs/show_bug.cgi?id=31058)
+    configs -= [ "//build/config/compiler:compiler_arm_thumb" ]
+    configs += [ "//build/config/compiler:compiler_arm" ]
+
     # TODO(crbug.com/633719) Make tcmalloc work with AFDO if possible.
     configs -= [ "//build/config/compiler:afdo" ]
 
diff --git a/base/run_loop.cc b/base/run_loop.cc
index a2322f8..6faaeee 100644
--- a/base/run_loop.cc
+++ b/base/run_loop.cc
@@ -25,6 +25,7 @@
 }
 
 void RunLoop::Run() {
+  DCHECK(thread_checker_.CalledOnValidThread());
   if (!BeforeRun())
     return;
 
@@ -44,6 +45,7 @@
 }
 
 void RunLoop::Quit() {
+  DCHECK(thread_checker_.CalledOnValidThread());
   quit_called_ = true;
   if (running_ && loop_->run_loop_ == this) {
     // This is the inner-most RunLoop, so quit now.
@@ -52,6 +54,7 @@
 }
 
 void RunLoop::QuitWhenIdle() {
+  DCHECK(thread_checker_.CalledOnValidThread());
   quit_when_idle_received_ = true;
 }
 
diff --git a/base/run_loop.h b/base/run_loop.h
index 635018f43..077d097b 100644
--- a/base/run_loop.h
+++ b/base/run_loop.h
@@ -10,6 +10,7 @@
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
 #include "base/message_loop/message_loop.h"
+#include "base/threading/thread_checker.h"
 #include "build/build_config.h"
 
 namespace base {
@@ -105,6 +106,8 @@
   // that we should quit Run once it becomes idle.
   bool quit_when_idle_received_;
 
+  base::ThreadChecker thread_checker_;
+
   // WeakPtrFactory for QuitClosure safety.
   base::WeakPtrFactory<RunLoop> weak_factory_;
 
diff --git a/build/config/compiler/BUILD.gn b/build/config/compiler/BUILD.gn
index 661245af..3c6470ae 100644
--- a/build/config/compiler/BUILD.gn
+++ b/build/config/compiler/BUILD.gn
@@ -779,6 +779,14 @@
   }
 }
 
+config("compiler_arm") {
+  if (current_cpu == "arm" && is_chromeos) {
+    # arm is normally the default mode for clang, but on chromeos a wrapper
+    # is used to pass -mthumb, and therefor change the default.
+    cflags = [ "-marm" ]
+  }
+}
+
 # runtime_library -------------------------------------------------------------
 #
 # Sets the runtime library and associated options.
diff --git a/chrome/app/chromeos_strings.grdp b/chrome/app/chromeos_strings.grdp
index e135107..02da47b 100644
--- a/chrome/app/chromeos_strings.grdp
+++ b/chrome/app/chromeos_strings.grdp
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!-- ChromeOS-specific strings (included from generated_resources.grd).
+<!-- Chrome OS-specific strings (included from generated_resources.grd).
      Everything in this file is wrapped in <if expr="chromeos">. -->
 <grit-part>
   <message name="IDS_EMPTY_STRING" desc="Empty string, exist only to make code generic. No translation required.">
@@ -6171,6 +6171,9 @@
   <message name="IDS_ENTERPRISE_ENROLLMENT_STATUS_NO_MACHINE_IDENTIFICATION" desc="Error message shown on the enrollment screen when the system failed to determine the device model or serial number.">
     Oops!  The system failed to determine device model or serial number.
   </message>
+  <message name="IDS_ENTERPRISE_ENROLLMENT_ERROR_ACTIVE_DIRECTORY_POLICY_FETCH" desc="Error message shown on the enrollment screen when the system failed to fetch device policy from Active Directory.">
+    Oops!  The system failed to fetch policy from Microsoft® Active Directory®.
+  </message>
   <message name="IDS_ENTERPRISE_ENROLLMENT_SCREEN_TITLE" desc="The title on the enterprise enrollment dialog.">
     Enterprise enrollment
   </message>
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index 6aae3e3d..66c921d 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -4278,6 +4278,8 @@
     sources += [
       "chromeos/app_mode/fake_cws.cc",
       "chromeos/app_mode/fake_cws.h",
+      "chromeos/arc/extensions/fake_arc_support.cc",
+      "chromeos/arc/extensions/fake_arc_support.h",
       "chromeos/file_manager/fake_disk_mount_manager.cc",
       "chromeos/file_manager/fake_disk_mount_manager.h",
       "chromeos/input_method/mock_candidate_window_controller.cc",
diff --git a/chrome/browser/chromeos/BUILD.gn b/chrome/browser/chromeos/BUILD.gn
index 19f18b12..ade3609 100644
--- a/chrome/browser/chromeos/BUILD.gn
+++ b/chrome/browser/chromeos/BUILD.gn
@@ -252,6 +252,8 @@
     "arc/optin/arc_optin_preference_handler.cc",
     "arc/optin/arc_optin_preference_handler.h",
     "arc/optin/arc_optin_preference_handler_delegate.h",
+    "arc/optin/arc_terms_of_service_negotiator.cc",
+    "arc/optin/arc_terms_of_service_negotiator.h",
     "arc/policy/arc_android_management_checker.cc",
     "arc/policy/arc_android_management_checker.h",
     "arc/policy/arc_android_management_checker_delegate.h",
@@ -1408,6 +1410,7 @@
     "arc/fileapi/arc_content_file_system_url_util_unittest.cc",
     "arc/intent_helper/arc_external_protocol_dialog_unittest.cc",
     "arc/intent_helper/arc_navigation_throttle_unittest.cc",
+    "arc/optin/arc_terms_of_service_negotiator_unittest.cc",
     "arc/policy/arc_policy_bridge_unittest.cc",
     "attestation/attestation_ca_client_unittest.cc",
     "attestation/attestation_policy_observer_unittest.cc",
diff --git a/chrome/browser/chromeos/arc/arc_session_manager.cc b/chrome/browser/chromeos/arc/arc_session_manager.cc
index 21effca8..2be4bdc2 100644
--- a/chrome/browser/chromeos/arc/arc_session_manager.cc
+++ b/chrome/browser/chromeos/arc/arc_session_manager.cc
@@ -19,7 +19,7 @@
 #include "chrome/browser/chromeos/arc/arc_optin_uma.h"
 #include "chrome/browser/chromeos/arc/arc_support_host.h"
 #include "chrome/browser/chromeos/arc/auth/arc_robot_auth.h"
-#include "chrome/browser/chromeos/arc/optin/arc_optin_preference_handler.h"
+#include "chrome/browser/chromeos/arc/optin/arc_terms_of_service_negotiator.h"
 #include "chrome/browser/chromeos/arc/policy/arc_android_management_checker.h"
 #include "chrome/browser/chromeos/arc/policy/arc_policy_util.h"
 #include "chrome/browser/chromeos/profiles/profile_helper.h"
@@ -377,11 +377,6 @@
     DCHECK(!support_host_);
     support_host_ = base::MakeUnique<ArcSupportHost>(profile_);
     support_host_->AddObserver(this);
-
-    preference_handler_ = base::MakeUnique<arc::ArcOptInPreferenceHandler>(
-        this, profile_->GetPrefs());
-    // This automatically updates all preferences.
-    preference_handler_->Start();
   }
 
   DCHECK_EQ(State::NOT_INITIALIZED, state_);
@@ -493,49 +488,65 @@
   if (support_host_)
     support_host_->SetArcManaged(IsArcManaged());
 
-  // In case UI is disabled we assume that ARC is opted-in. For ARC Kiosk we
-  // skip ToS because it is very likely that near the device there will be
-  // no one who is eligible to accept them. We skip if Android management check
-  // because there are no managed human users for Kiosk exist.
-  if (IsOptInVerificationDisabled() || IsArcKioskMode()) {
-    // Automatically accept terms in kiosk mode. This is not required for
-    // IsOptInVerificationDisabled mode because in last case it may cause
-    // a privacy issue on next run without this flag set.
-    if (IsArcKioskMode())
-      profile_->GetPrefs()->SetBoolean(prefs::kArcTermsAccepted, true);
-    StartArc();
-    return;
-  }
+  // For ARC Kiosk we skip ToS because it is very likely that near the device
+  // there will be no one who is eligible to accept them.
+  // TODO(poromov): Move to more Kiosk dedicated set-up phase.
+  if (IsArcKioskMode())
+    profile_->GetPrefs()->SetBoolean(prefs::kArcTermsAccepted, true);
 
-  if (!profile_->GetPrefs()->GetBoolean(prefs::kArcSignedIn)) {
-    if (profile_->GetPrefs()->GetBoolean(prefs::kArcTermsAccepted)) {
-      StartArc();
-    } else {
-      // Need pre-fetch auth code and show OptIn UI if needed.
-      StartUI();
-    }
-  } else {
-    // Ready to start Arc, but check Android management in parallel.
+  // If it is marked that sign in has been successfully done, then directly
+  // start ARC.
+  // For testing, and for Kisok mode, we also skip ToS negotiation procedure.
+  // For backward compatibility, this check needs to be prior to the
+  // kArcTermsAccepted check below.
+  if (profile_->GetPrefs()->GetBoolean(prefs::kArcSignedIn) ||
+      IsOptInVerificationDisabled() || IsArcKioskMode()) {
     StartArc();
+
+    // Skip Android management check for testing.
+    // We also skip if Android management check for Kiosk mode,
+    // because there are no managed human users for Kiosk exist.
+    if (IsOptInVerificationDisabled() || IsArcKioskMode() ||
+        (g_disable_ui_for_testing &&
+         !g_enable_check_android_management_for_testing)) {
+      return;
+    }
+
+    // Check Android management in parallel.
     // Note: Because the callback may be called in synchronous way (i.e. called
     // on the same stack), StartCheck() needs to be called *after* StartArc().
     // Otherwise, DisableArc() which may be called in
     // OnBackgroundAndroidManagementChecked() could be ignored.
-    if (!g_disable_ui_for_testing ||
-        g_enable_check_android_management_for_testing) {
-      android_management_checker_.reset(new ArcAndroidManagementChecker(
-          profile_, context_->token_service(), context_->account_id(),
-          true /* retry_on_error */));
-      android_management_checker_->StartCheck(
-          base::Bind(&ArcSessionManager::OnBackgroundAndroidManagementChecked,
-                     weak_ptr_factory_.GetWeakPtr()));
-    }
+    android_management_checker_ = base::MakeUnique<ArcAndroidManagementChecker>(
+        profile_, context_->token_service(), context_->account_id(),
+        true /* retry_on_error */);
+    android_management_checker_->StartCheck(
+        base::Bind(&ArcSessionManager::OnBackgroundAndroidManagementChecked,
+                   weak_ptr_factory_.GetWeakPtr()));
+    return;
   }
+
+  // If it is marked that the Terms of service is accepted already,
+  // just skip the negotiation with user, and start Android management
+  // check directly.
+  // This happens, e.g., when;
+  // 1) User accepted the Terms of service on OOBE flow.
+  // 2) User accepted the Terms of service on Opt-in flow, but logged out
+  //   before ARC sign in procedure was done. Then, logs in again.
+  if (profile_->GetPrefs()->GetBoolean(prefs::kArcTermsAccepted)) {
+    support_host_->ShowArcLoading();
+    StartArcAndroidManagementCheck();
+    return;
+  }
+
+  // Need user's explicit Terms Of Service agreement.
+  StartTermsOfServiceNegotiation();
 }
 
 void ArcSessionManager::ShutdownBridge() {
   arc_sign_in_timer_.Stop();
   playstore_launcher_.reset();
+  terms_of_service_negotiator_.reset();
   android_management_checker_.reset();
   arc_bridge_service()->RequestStop();
   if (state_ != State::NOT_INITIALIZED)
@@ -648,8 +659,9 @@
     UpdateEnabledStateUMA(IsArcEnabled());
 }
 
-void ArcSessionManager::StartUI() {
+void ArcSessionManager::StartTermsOfServiceNegotiation() {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+  DCHECK(!terms_of_service_negotiator_);
 
   if (!arc_bridge_service()->stopped()) {
     // If the user attempts to re-enable ARC while the bridge is still running
@@ -662,8 +674,32 @@
   }
 
   SetState(State::SHOWING_TERMS_OF_SERVICE);
-  if (support_host_)
-    support_host_->ShowTermsOfService();
+  if (support_host_) {
+    terms_of_service_negotiator_ =
+        base::MakeUnique<ArcTermsOfServiceNegotiator>(profile_->GetPrefs(),
+                                                      support_host_.get());
+    terms_of_service_negotiator_->StartNegotiation(
+        base::Bind(&ArcSessionManager::OnTermsOfServiceNegotiated,
+                   weak_ptr_factory_.GetWeakPtr()));
+  }
+}
+
+void ArcSessionManager::OnTermsOfServiceNegotiated(bool accepted) {
+  DCHECK(terms_of_service_negotiator_);
+  terms_of_service_negotiator_.reset();
+
+  if (!accepted) {
+    // To cancel, user needs to close the window. Note that clicking "Cancel"
+    // button effectively just closes the window.
+    CancelAuthCode();
+    return;
+  }
+
+  // Terms were accepted.
+  profile_->GetPrefs()->SetBoolean(prefs::kArcTermsAccepted, true);
+
+  support_host_->ShowArcLoading();
+  StartArcAndroidManagementCheck();
 }
 
 void ArcSessionManager::StartArcAndroidManagementCheck() {
@@ -734,6 +770,11 @@
 
 void ArcSessionManager::OnWindowClosed() {
   DCHECK(support_host_);
+  if (terms_of_service_negotiator_) {
+    // In this case, ArcTermsOfServiceNegotiator should handle the case.
+    // Do nothing.
+    return;
+  }
   CancelAuthCode();
 }
 
@@ -741,19 +782,8 @@
                                       bool is_backup_and_restore_enabled,
                                       bool is_location_service_enabled) {
   DCHECK(support_host_);
-
-  // Terms were accepted
-  profile_->GetPrefs()->SetBoolean(prefs::kArcTermsAccepted, true);
-
-  // Since this is ARC support's UI event callback, preference_handler_
-  // should be always created (see OnPrimaryUserProfilePrepared()).
-  // TODO(hidehiko): Simplify the logic with the code restructuring.
-  DCHECK(preference_handler_);
-  preference_handler_->EnableMetrics(is_metrics_enabled);
-  preference_handler_->EnableBackupRestore(is_backup_and_restore_enabled);
-  preference_handler_->EnableLocationService(is_location_service_enabled);
-  support_host_->ShowArcLoading();
-  StartArcAndroidManagementCheck();
+  DCHECK(terms_of_service_negotiator_);
+  // This should be handled in ArcTermsOfServiceNegotiator. Do nothing here.
 }
 
 void ArcSessionManager::OnRetryClicked() {
@@ -762,9 +792,11 @@
   UpdateOptInActionUMA(OptInActionType::RETRY);
 
   // TODO(hidehiko): Simplify the retry logic.
-  if (!profile_->GetPrefs()->GetBoolean(prefs::kArcTermsAccepted)) {
-    // If the user has not yet agreed on Terms of Service, then show it.
-    support_host_->ShowTermsOfService();
+  if (terms_of_service_negotiator_) {
+    // Currently Terms of service is shown. ArcTermsOfServiceNegotiator should
+    // handle this.
+  } else if (!profile_->GetPrefs()->GetBoolean(prefs::kArcTermsAccepted)) {
+    StartTermsOfServiceNegotiation();
   } else if (support_host_->ui_page() == ArcSupportHost::UIPage::ERROR &&
              !arc_bridge_service()->stopped()) {
     // ERROR_WITH_FEEDBACK is set in OnSignInFailed(). In the case, stopping
@@ -791,26 +823,6 @@
   chrome::OpenFeedbackDialog(nullptr);
 }
 
-void ArcSessionManager::OnMetricsModeChanged(bool enabled, bool managed) {
-  if (!support_host_)
-    return;
-  support_host_->SetMetricsPreferenceCheckbox(enabled, managed);
-}
-
-void ArcSessionManager::OnBackupAndRestoreModeChanged(bool enabled,
-                                                      bool managed) {
-  if (!support_host_)
-    return;
-  support_host_->SetBackupAndRestorePreferenceCheckbox(enabled, managed);
-}
-
-void ArcSessionManager::OnLocationServicesModeChanged(bool enabled,
-                                                      bool managed) {
-  if (!support_host_)
-    return;
-  support_host_->SetLocationServicesPreferenceCheckbox(enabled, managed);
-}
-
 std::ostream& operator<<(std::ostream& os,
                          const ArcSessionManager::State& state) {
   switch (state) {
diff --git a/chrome/browser/chromeos/arc/arc_session_manager.h b/chrome/browser/chromeos/arc/arc_session_manager.h
index a4e6bbc4..8c14697 100644
--- a/chrome/browser/chromeos/arc/arc_session_manager.h
+++ b/chrome/browser/chromeos/arc/arc_session_manager.h
@@ -14,7 +14,6 @@
 #include "base/observer_list.h"
 #include "base/timer/timer.h"
 #include "chrome/browser/chromeos/arc/arc_support_host.h"
-#include "chrome/browser/chromeos/arc/optin/arc_optin_preference_handler_observer.h"
 #include "chrome/browser/chromeos/policy/android_management_client.h"
 #include "components/arc/arc_bridge_service.h"
 #include "components/arc/arc_service.h"
@@ -39,7 +38,7 @@
 class ArcAndroidManagementChecker;
 class ArcAuthCodeFetcher;
 class ArcAuthContext;
-class ArcOptInPreferenceHandler;
+class ArcTermsOfServiceNegotiator;
 enum class ProvisioningResult : int;
 
 // This class proxies the request from the client to fetch an auth code from
@@ -47,7 +46,6 @@
 class ArcSessionManager : public ArcService,
                           public ArcBridgeService::Observer,
                           public ArcSupportHost::Observer,
-                          public ArcOptInPreferenceHandlerObserver,
                           public sync_preferences::PrefServiceSyncableObserver,
                           public sync_preferences::SyncedPrefObserver {
  public:
@@ -181,11 +179,6 @@
   void OnRetryClicked() override;
   void OnSendFeedbackClicked() override;
 
-  // ArcOptInPreferenceHandlerObserver:
-  void OnMetricsModeChanged(bool enabled, bool managed) override;
-  void OnBackupAndRestoreModeChanged(bool enabled, bool managed) override;
-  void OnLocationServicesModeChanged(bool enabled, bool managed) override;
-
   // Stops ARC without changing ArcEnabled preference.
   void StopArc();
 
@@ -209,11 +202,13 @@
   void OnProvisioningFinished(ProvisioningResult result);
 
  private:
-  // TODO(hidehiko): move UI methods/fields to ArcSupportHost.
+  // Negotiates the terms of service to user.
+  void StartTermsOfServiceNegotiation();
+  void OnTermsOfServiceNegotiated(bool accepted);
+
   void SetState(State state);
   void ShutdownBridge();
   void OnOptInPreferenceChanged();
-  void StartUI();
   void OnAndroidManagementPassed();
   void OnArcDataRemoved(bool success);
   void OnArcSignInTimeout();
@@ -245,12 +240,9 @@
   bool reenable_arc_ = false;
   base::OneShotTimer arc_sign_in_timer_;
 
-  // Temporarily keeps the ArcSupportHost instance.
-  // This should be moved to ArcSessionManager when the refactoring is
-  // done.
   std::unique_ptr<ArcSupportHost> support_host_;
-  // Handles preferences and metrics mode.
-  std::unique_ptr<ArcOptInPreferenceHandler> preference_handler_;
+
+  std::unique_ptr<ArcTermsOfServiceNegotiator> terms_of_service_negotiator_;
 
   std::unique_ptr<ArcAuthContext> context_;
   std::unique_ptr<ArcAndroidManagementChecker> android_management_checker_;
diff --git a/chrome/browser/chromeos/arc/arc_session_manager_browsertest.cc b/chrome/browser/chromeos/arc/arc_session_manager_browsertest.cc
index e8f90f1..6b6db154 100644
--- a/chrome/browser/chromeos/arc/arc_session_manager_browsertest.cc
+++ b/chrome/browser/chromeos/arc/arc_session_manager_browsertest.cc
@@ -153,6 +153,7 @@
     token_service_->UpdateCredentials("", kRefreshToken);
 
     profile()->GetPrefs()->SetBoolean(prefs::kArcSignedIn, true);
+    profile()->GetPrefs()->SetBoolean(prefs::kArcTermsAccepted, true);
 
     const AccountId account_id(
         AccountId::FromUserEmailGaiaId(kFakeUserName, "1234567890"));
diff --git a/chrome/browser/chromeos/arc/arc_session_manager_unittest.cc b/chrome/browser/chromeos/arc/arc_session_manager_unittest.cc
index 574acaa..7403af09 100644
--- a/chrome/browser/chromeos/arc/arc_session_manager_unittest.cc
+++ b/chrome/browser/chromeos/arc/arc_session_manager_unittest.cc
@@ -288,6 +288,8 @@
   arc_session_manager()->OnPrimaryUserProfilePrepared(profile());
   EXPECT_EQ(ArcSessionManager::State::SHOWING_TERMS_OF_SERVICE,
             arc_session_manager()->state());
+  // Emulate to accept the terms of service.
+  prefs->SetBoolean(prefs::kArcTermsAccepted, true);
   arc_session_manager()->StartArc();
   EXPECT_EQ(ArcSessionManager::State::ACTIVE, arc_session_manager()->state());
   EXPECT_TRUE(bridge_service()->ready());
diff --git a/chrome/browser/chromeos/arc/arc_support_host.cc b/chrome/browser/chromeos/arc/arc_support_host.cc
index 5e072ad..3941d5d 100644
--- a/chrome/browser/chromeos/arc/arc_support_host.cc
+++ b/chrome/browser/chromeos/arc/arc_support_host.cc
@@ -8,6 +8,7 @@
 #include <utility>
 
 #include "ash/common/system/chromeos/devicetype_utils.h"
+#include "base/bind.h"
 #include "base/i18n/timezone.h"
 #include "base/json/json_reader.h"
 #include "base/json/json_writer.h"
@@ -86,6 +87,18 @@
 // "onSendFeedbackClicked" is fired when a user clicks "Send Feedback" button.
 constexpr char kEventOnSendFeedbackClicked[] = "onSendFeedbackClicked";
 
+void RequestOpenApp(Profile* profile) {
+  const extensions::Extension* extension =
+      extensions::ExtensionRegistry::Get(profile)->GetInstalledExtension(
+          ArcSupportHost::kHostAppId);
+  DCHECK(extension);
+  DCHECK(
+      extensions::util::IsAppLaunchable(ArcSupportHost::kHostAppId, profile));
+  OpenApplication(CreateAppLaunchParamsUserContainer(
+      profile, extension, WindowOpenDisposition::NEW_WINDOW,
+      extensions::SOURCE_CHROME_INTERNAL));
+}
+
 std::ostream& operator<<(std::ostream& os, ArcSupportHost::UIPage ui_page) {
   switch (ui_page) {
     case ArcSupportHost::UIPage::NO_PAGE:
@@ -140,7 +153,11 @@
 // static
 const char ArcSupportHost::kStorageId[] = "arc_support";
 
-ArcSupportHost::ArcSupportHost(Profile* profile) : profile_(profile) {}
+ArcSupportHost::ArcSupportHost(Profile* profile)
+    : profile_(profile),
+      request_open_app_callback_(base::Bind(&RequestOpenApp)) {
+  DCHECK(profile_);
+}
 
 ArcSupportHost::~ArcSupportHost() {
   if (message_host_)
@@ -317,7 +334,9 @@
     DisconnectMessageHost();
   message_host_ = message_host;
   message_host_->SetObserver(this);
-  display::Screen::GetScreen()->AddObserver(this);
+  display::Screen* screen = display::Screen::GetScreen();
+  if (screen)
+    screen->AddObserver(this);
 
   if (!Initialize()) {
     Close();
@@ -352,7 +371,9 @@
 
 void ArcSupportHost::DisconnectMessageHost() {
   DCHECK(message_host_);
-  display::Screen::GetScreen()->RemoveObserver(this);
+  display::Screen* screen = display::Screen::GetScreen();
+  if (screen)
+    screen->RemoveObserver(this);
   message_host_->SetObserver(nullptr);
   message_host_ = nullptr;
 }
@@ -362,14 +383,15 @@
   DCHECK(!app_start_pending_);
 
   app_start_pending_ = true;
-  const extensions::Extension* extension =
-      extensions::ExtensionRegistry::Get(profile_)->GetInstalledExtension(
-          kHostAppId);
-  DCHECK(extension);
-  DCHECK(extensions::util::IsAppLaunchable(kHostAppId, profile_));
-  OpenApplication(CreateAppLaunchParamsUserContainer(
-      profile_, extension, WindowOpenDisposition::NEW_WINDOW,
-      extensions::SOURCE_CHROME_INTERNAL));
+  request_open_app_callback_.Run(profile_);
+}
+
+void ArcSupportHost::SetRequestOpenAppCallbackForTesting(
+    const RequestOpenAppCallback& callback) {
+  DCHECK(!message_host_);
+  DCHECK(!app_start_pending_);
+  DCHECK(!callback.is_null());
+  request_open_app_callback_ = callback;
 }
 
 bool ArcSupportHost::Initialize() {
@@ -463,7 +485,6 @@
 
   const std::string device_id = user_manager::known_user::GetDeviceId(
       multi_user_util::GetAccountIdFromProfile(profile_));
-  DCHECK(!device_id.empty());
   message.SetString(kDeviceId, device_id);
 
   message_host_->SendMessage(message);
diff --git a/chrome/browser/chromeos/arc/arc_support_host.h b/chrome/browser/chromeos/arc/arc_support_host.h
index 1712611a..9a33c41 100644
--- a/chrome/browser/chromeos/arc/arc_support_host.h
+++ b/chrome/browser/chromeos/arc/arc_support_host.h
@@ -8,6 +8,7 @@
 #include <memory>
 #include <string>
 
+#include "base/callback.h"
 #include "base/macros.h"
 #include "base/observer_list.h"
 #include "chrome/browser/chromeos/arc/extensions/arc_support_message_host.h"
@@ -51,8 +52,6 @@
     virtual void OnWindowClosed() {}
 
     // Called when the user press AGREE button on ToS page.
-    // TODO(hidehiko): Currently, due to implementation reason,
-    // this is also called when RETRY on error page is clicked. Fix this.
     virtual void OnTermsAgreed(bool is_metrics_enabled,
                                bool is_backup_and_restore_enabled,
                                bool is_location_service_enabled) {}
@@ -70,6 +69,8 @@
   static const char kHostAppId[];
   static const char kStorageId[];
 
+  using RequestOpenAppCallback = base::Callback<void(Profile* profile)>;
+
   explicit ArcSupportHost(Profile* profile);
   ~ArcSupportHost() override;
 
@@ -124,6 +125,9 @@
   // TODO(hidehiko): Remove this exposure.
   UIPage ui_page() const { return ui_page_; }
 
+  void SetRequestOpenAppCallbackForTesting(
+      const RequestOpenAppCallback& callback);
+
  private:
   struct PreferenceCheckboxData {
     PreferenceCheckboxData() : PreferenceCheckboxData(false, false) {}
@@ -155,6 +159,7 @@
   void DisconnectMessageHost();
 
   Profile* const profile_;
+  RequestOpenAppCallback request_open_app_callback_;
 
   base::ObserverList<Observer> observer_list_;
 
diff --git a/chrome/browser/chromeos/arc/extensions/fake_arc_support.cc b/chrome/browser/chromeos/arc/extensions/fake_arc_support.cc
new file mode 100644
index 0000000..2b2063a
--- /dev/null
+++ b/chrome/browser/chromeos/arc/extensions/fake_arc_support.cc
@@ -0,0 +1,127 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/chromeos/arc/extensions/fake_arc_support.h"
+
+#include <string>
+
+#include "base/bind.h"
+#include "base/json/json_reader.h"
+#include "base/json/json_writer.h"
+#include "base/logging.h"
+#include "base/values.h"
+#include "chrome/browser/chromeos/arc/extensions/arc_support_message_host.h"
+
+namespace arc {
+
+FakeArcSupport::FakeArcSupport(ArcSupportHost* support_host)
+    : support_host_(support_host), weak_ptr_factory_(this) {
+  DCHECK(support_host_);
+  support_host_->SetRequestOpenAppCallbackForTesting(
+      base::Bind(&FakeArcSupport::Open, weak_ptr_factory_.GetWeakPtr()));
+}
+
+FakeArcSupport::~FakeArcSupport() {
+  // Ensure that message host is disconnected.
+  if (native_message_host_)
+    Close();
+}
+
+void FakeArcSupport::Open(Profile* profile) {
+  DCHECK(!native_message_host_);
+  native_message_host_ = ArcSupportMessageHost::Create();
+  native_message_host_->Start(this);
+  support_host_->SetMessageHost(
+      static_cast<ArcSupportMessageHost*>(native_message_host_.get()));
+}
+
+void FakeArcSupport::Close() {
+  DCHECK(native_message_host_);
+  native_message_host_->OnMessage("{\"event\": \"onWindowClosed\"}");
+  support_host_->UnsetMessageHost(
+      static_cast<ArcSupportMessageHost*>(native_message_host_.get()));
+  native_message_host_.reset();
+}
+
+void FakeArcSupport::ClickAgreeButton() {
+  DCHECK(native_message_host_);
+  DCHECK_EQ(ui_page_, ArcSupportHost::UIPage::TERMS);
+
+  base::DictionaryValue message;
+  message.SetString("event", "onAgreed");
+  message.SetBoolean("isMetricsEnabled", metrics_mode_);
+  message.SetBoolean("isBackupRestoreEnabled", backup_and_restore_mode_);
+  message.SetBoolean("isLocationServiceEnabled", location_service_mode_);
+
+  std::string message_string;
+  if (!base::JSONWriter::Write(message, &message_string)) {
+    NOTREACHED();
+    return;
+  }
+  native_message_host_->OnMessage(message_string);
+}
+
+void FakeArcSupport::ClickRetryButton() {
+  DCHECK(native_message_host_);
+  DCHECK_EQ(ui_page_, ArcSupportHost::UIPage::ERROR);
+  native_message_host_->OnMessage("{\"event\": \"onRetryClicked\"}");
+}
+
+void FakeArcSupport::PostMessageFromNativeHost(
+    const std::string& message_string) {
+  std::unique_ptr<base::DictionaryValue> message =
+      base::DictionaryValue::From(base::JSONReader::Read(message_string));
+  DCHECK(message);
+
+  std::string action;
+  if (!message->GetString("action", &action)) {
+    NOTREACHED() << message_string;
+    return;
+  }
+
+  if (action == "initialize") {
+    // Do nothing as emulation.
+  } else if (action == "showPage") {
+    std::string page;
+    if (!message->GetString("page", &page)) {
+      NOTREACHED() << message_string;
+      return;
+    }
+    if (page == "terms") {
+      ui_page_ = ArcSupportHost::UIPage::TERMS;
+    } else if (page == "lso-loading") {
+      ui_page_ = ArcSupportHost::UIPage::LSO;
+    } else if (page == "arc-loading") {
+      ui_page_ = ArcSupportHost::UIPage::ARC_LOADING;
+    } else {
+      NOTREACHED() << message_string;
+    }
+  } else if (action == "showErrorPage") {
+    ui_page_ = ArcSupportHost::UIPage::ERROR;
+  } else if (action == "setMetricsMode") {
+    if (!message->GetBoolean("enabled", &metrics_mode_)) {
+      NOTREACHED() << message_string;
+      return;
+    }
+  } else if (action == "setBackupAndRestoreMode") {
+    if (!message->GetBoolean("enabled", &backup_and_restore_mode_)) {
+      NOTREACHED() << message_string;
+      return;
+    }
+  } else if (action == "setLocationServiceMode") {
+    if (!message->GetBoolean("enabled", &location_service_mode_)) {
+      NOTREACHED() << message_string;
+      return;
+    }
+  } else {
+    // Unknown or unsupported action.
+    NOTREACHED() << message_string;
+  }
+}
+
+void FakeArcSupport::CloseChannel(const std::string& error_message) {
+  NOTREACHED();
+}
+
+}  // namespace arc
diff --git a/chrome/browser/chromeos/arc/extensions/fake_arc_support.h b/chrome/browser/chromeos/arc/extensions/fake_arc_support.h
new file mode 100644
index 0000000..a0af1b5
--- /dev/null
+++ b/chrome/browser/chromeos/arc/extensions/fake_arc_support.h
@@ -0,0 +1,68 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_CHROMEOS_ARC_EXTENSIONS_FAKE_ARC_SUPPORT_H_
+#define CHROME_BROWSER_CHROMEOS_ARC_EXTENSIONS_FAKE_ARC_SUPPORT_H_
+
+#include <memory>
+#include <string>
+
+#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
+#include "chrome/browser/chromeos/arc/arc_support_host.h"
+#include "extensions/browser/api/messaging/native_message_host.h"
+
+namespace arc {
+
+// Fake implementation of ARC support Chrome App for testing.
+class FakeArcSupport : public extensions::NativeMessageHost::Client {
+ public:
+  explicit FakeArcSupport(ArcSupportHost* support_host);
+  ~FakeArcSupport() override;
+
+  // Emulates to open ARC support Chrome app, and connect message host to
+  // ARC support host.
+  void Open(Profile* profile);
+
+  // Emulates clicking Close button.
+  void Close();
+
+  // Terms of service page emulation.
+  // Emulates clicking Agree button.
+  void ClickAgreeButton();
+
+  // Emulates checking preference box.
+  void set_metrics_mode(bool mode) { metrics_mode_ = mode; }
+  void set_backup_and_restore_mode(bool mode) {
+    backup_and_restore_mode_ = mode;
+  }
+  void set_location_service_mode(bool mode) { location_service_mode_ = mode; }
+
+  // Error page emulation.
+  void ClickRetryButton();
+
+  // Returns the current page.
+  ArcSupportHost::UIPage ui_page() const { return ui_page_; }
+
+ private:
+  // extensions::NativeMessageHost::Client:
+  void PostMessageFromNativeHost(const std::string& message) override;
+  void CloseChannel(const std::string& error_message) override;
+
+  ArcSupportHost* const support_host_;
+
+  std::unique_ptr<extensions::NativeMessageHost> native_message_host_;
+  ArcSupportHost::UIPage ui_page_ = ArcSupportHost::UIPage::NO_PAGE;
+  bool metrics_mode_ = false;
+  bool backup_and_restore_mode_ = false;
+  bool location_service_mode_ = false;
+
+  base::WeakPtrFactory<FakeArcSupport> weak_ptr_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(FakeArcSupport);
+};
+
+}  // namespace arc
+
+#endif  // CHROME_BROWSER_CHROMEOS_ARC_EXTENSIONS_FAKE_ARC_SUPPORT_H_
diff --git a/chrome/browser/chromeos/arc/optin/arc_optin_preference_handler.cc b/chrome/browser/chromeos/arc/optin/arc_optin_preference_handler.cc
index 4eac145e..11972d6 100644
--- a/chrome/browser/chromeos/arc/optin/arc_optin_preference_handler.cc
+++ b/chrome/browser/chromeos/arc/optin/arc_optin_preference_handler.cc
@@ -24,12 +24,13 @@
 }
 
 void ArcOptInPreferenceHandler::Start() {
-  DCHECK(g_browser_process->local_state());
-  pref_local_change_registrar_.Init(g_browser_process->local_state());
-  pref_local_change_registrar_.Add(
-      metrics::prefs::kMetricsReportingEnabled,
-      base::Bind(&ArcOptInPreferenceHandler::OnMetricsPreferenceChanged,
-                 base::Unretained(this)));
+  if (g_browser_process->local_state()) {
+    pref_local_change_registrar_.Init(g_browser_process->local_state());
+    pref_local_change_registrar_.Add(
+        metrics::prefs::kMetricsReportingEnabled,
+        base::Bind(&ArcOptInPreferenceHandler::OnMetricsPreferenceChanged,
+                   base::Unretained(this)));
+  }
 
   pref_change_registrar_.Init(pref_service_);
   pref_change_registrar_.Add(
@@ -63,9 +64,11 @@
 }
 
 void ArcOptInPreferenceHandler::SendMetricsMode() {
-  observer_->OnMetricsModeChanged(
-      ChromeMetricsServiceAccessor::IsMetricsAndCrashReportingEnabled(),
-      IsMetricsReportingPolicyManaged());
+  if (g_browser_process->local_state()) {
+    observer_->OnMetricsModeChanged(
+        ChromeMetricsServiceAccessor::IsMetricsAndCrashReportingEnabled(),
+        IsMetricsReportingPolicyManaged());
+  }
 }
 
 void ArcOptInPreferenceHandler::SendBackupAndRestoreMode() {
@@ -81,7 +84,8 @@
 }
 
 void ArcOptInPreferenceHandler::EnableMetrics(bool is_enabled) {
-  ChangeMetricsReportingState(is_enabled);
+  if (g_browser_process->local_state())
+    ChangeMetricsReportingState(is_enabled);
 }
 
 void ArcOptInPreferenceHandler::EnableBackupRestore(bool is_enabled) {
diff --git a/chrome/browser/chromeos/arc/optin/arc_terms_of_service_negotiator.cc b/chrome/browser/chromeos/arc/optin/arc_terms_of_service_negotiator.cc
new file mode 100644
index 0000000..8214aa5a
--- /dev/null
+++ b/chrome/browser/chromeos/arc/optin/arc_terms_of_service_negotiator.cc
@@ -0,0 +1,98 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/chromeos/arc/optin/arc_terms_of_service_negotiator.h"
+
+#include <string>
+
+#include "base/callback_helpers.h"
+#include "base/macros.h"
+#include "base/memory/ptr_util.h"
+#include "chrome/browser/chromeos/arc/optin/arc_optin_preference_handler.h"
+
+namespace arc {
+
+ArcTermsOfServiceNegotiator::ArcTermsOfServiceNegotiator(
+    PrefService* pref_service,
+    ArcSupportHost* support_host)
+    : pref_service_(pref_service), support_host_(support_host) {
+  DCHECK(pref_service_);
+  DCHECK(support_host_);
+}
+
+ArcTermsOfServiceNegotiator::~ArcTermsOfServiceNegotiator() {
+  support_host_->RemoveObserver(this);
+}
+
+void ArcTermsOfServiceNegotiator::StartNegotiation(
+    const NegotiationCallback& callback) {
+  DCHECK(pending_callback_.is_null());
+  DCHECK(!preference_handler_);
+  pending_callback_ = callback;
+  preference_handler_ =
+      base::MakeUnique<ArcOptInPreferenceHandler>(this, pref_service_);
+  // This automatically updates all preferences.
+  preference_handler_->Start();
+
+  support_host_->AddObserver(this);
+  support_host_->ShowTermsOfService();
+}
+
+void ArcTermsOfServiceNegotiator::OnWindowClosed() {
+  DCHECK(!pending_callback_.is_null());
+  DCHECK(preference_handler_);
+  support_host_->RemoveObserver(this);
+  preference_handler_.reset();
+
+  // User cancels terms-of-service agreement UI by clicking "Cancel" button
+  // or closing the window directly.
+  base::ResetAndReturn(&pending_callback_).Run(false);
+}
+
+void ArcTermsOfServiceNegotiator::OnTermsAgreed(
+    bool is_metrics_enabled,
+    bool is_backup_and_restore_enabled,
+    bool is_location_service_enabled) {
+  DCHECK(!pending_callback_.is_null());
+  DCHECK(preference_handler_);
+  support_host_->RemoveObserver(this);
+
+  // Update the preferences with the value passed from UI.
+  preference_handler_->EnableMetrics(is_metrics_enabled);
+  preference_handler_->EnableBackupRestore(is_backup_and_restore_enabled);
+  preference_handler_->EnableLocationService(is_location_service_enabled);
+  preference_handler_.reset();
+
+  base::ResetAndReturn(&pending_callback_).Run(true);
+}
+
+void ArcTermsOfServiceNegotiator::OnAuthSucceeded(
+    const std::string& auth_code) {
+  NOTREACHED();
+}
+
+void ArcTermsOfServiceNegotiator::OnRetryClicked() {
+  support_host_->ShowTermsOfService();
+}
+
+void ArcTermsOfServiceNegotiator::OnSendFeedbackClicked() {
+  NOTREACHED();
+}
+
+void ArcTermsOfServiceNegotiator::OnMetricsModeChanged(bool enabled,
+                                                       bool managed) {
+  support_host_->SetMetricsPreferenceCheckbox(enabled, managed);
+}
+
+void ArcTermsOfServiceNegotiator::OnBackupAndRestoreModeChanged(bool enabled,
+                                                                bool managed) {
+  support_host_->SetBackupAndRestorePreferenceCheckbox(enabled, managed);
+}
+
+void ArcTermsOfServiceNegotiator::OnLocationServicesModeChanged(bool enabled,
+                                                                bool managed) {
+  support_host_->SetLocationServicesPreferenceCheckbox(enabled, managed);
+}
+
+}  // namespace arc
diff --git a/chrome/browser/chromeos/arc/optin/arc_terms_of_service_negotiator.h b/chrome/browser/chromeos/arc/optin/arc_terms_of_service_negotiator.h
new file mode 100644
index 0000000..41871dde
--- /dev/null
+++ b/chrome/browser/chromeos/arc/optin/arc_terms_of_service_negotiator.h
@@ -0,0 +1,66 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_CHROMEOS_ARC_OPTIN_ARC_TERMS_OF_SERVICE_NEGOTIATOR_H_
+#define CHROME_BROWSER_CHROMEOS_ARC_OPTIN_ARC_TERMS_OF_SERVICE_NEGOTIATOR_H_
+
+#include <memory>
+#include <string>
+
+#include "base/callback.h"
+#include "base/macros.h"
+#include "chrome/browser/chromeos/arc/arc_support_host.h"
+#include "chrome/browser/chromeos/arc/optin/arc_optin_preference_handler_observer.h"
+
+class PrefService;
+
+namespace arc {
+
+class ArcOptInPreferenceHandler;
+
+// Handles the Terms-of-service agreement user action.
+class ArcTermsOfServiceNegotiator : public ArcSupportHost::Observer,
+                                    public ArcOptInPreferenceHandlerObserver {
+ public:
+  ArcTermsOfServiceNegotiator(PrefService* pref_service,
+                              ArcSupportHost* support_host);
+  ~ArcTermsOfServiceNegotiator() override;
+
+  // Shows "Terms of service" page on ARC support Chrome App. Invokes the
+  // |callback| asynchronously with "|agreed| = true" if user agrees it.
+  // Otherwise (e.g., user clicks "Cancel" or closes the window), invokes
+  // |callback| with |agreed| = false.
+  // Deleting this instance cancels the operation, so |callback| will never
+  // be invoked then.
+  using NegotiationCallback = base::Callback<void(bool accepted)>;
+  void StartNegotiation(const NegotiationCallback& callback);
+
+ private:
+  // ArcSupportHost::Observer:
+  void OnWindowClosed() override;
+  void OnTermsAgreed(bool is_metrics_enabled,
+                     bool is_backup_and_restore_enabled,
+                     bool is_location_service_enabled) override;
+  void OnAuthSucceeded(const std::string& auth_code) override;
+  void OnRetryClicked() override;
+  void OnSendFeedbackClicked() override;
+
+  // ArcOptInPreferenceHandlerObserver:
+  void OnMetricsModeChanged(bool enabled, bool managed) override;
+  void OnBackupAndRestoreModeChanged(bool enabled, bool managed) override;
+  void OnLocationServicesModeChanged(bool enabled, bool managed) override;
+
+  PrefService* const pref_service_;
+  // Owned by ArcSessionManager.
+  ArcSupportHost* const support_host_;
+
+  NegotiationCallback pending_callback_;
+  std::unique_ptr<ArcOptInPreferenceHandler> preference_handler_;
+
+  DISALLOW_COPY_AND_ASSIGN(ArcTermsOfServiceNegotiator);
+};
+
+}  // namespace arc
+
+#endif  // CHROME_BROWSER_CHROMEOS_ARC_OPTIN_ARC_TERMS_OF_SERVICE_NEGOTIATOR_H_
diff --git a/chrome/browser/chromeos/arc/optin/arc_terms_of_service_negotiator_unittest.cc b/chrome/browser/chromeos/arc/optin/arc_terms_of_service_negotiator_unittest.cc
new file mode 100644
index 0000000..4feb871
--- /dev/null
+++ b/chrome/browser/chromeos/arc/optin/arc_terms_of_service_negotiator_unittest.cc
@@ -0,0 +1,193 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <memory>
+#include <ostream>
+
+#include "base/bind.h"
+#include "base/macros.h"
+#include "base/memory/ptr_util.h"
+#include "base/run_loop.h"
+#include "chrome/browser/chromeos/arc/arc_support_host.h"
+#include "chrome/browser/chromeos/arc/extensions/fake_arc_support.h"
+#include "chrome/browser/chromeos/arc/optin/arc_terms_of_service_negotiator.h"
+#include "chrome/browser/chromeos/login/users/fake_chrome_user_manager.h"
+#include "chrome/browser/chromeos/login/users/scoped_user_manager_enabler.h"
+#include "chrome/common/pref_names.h"
+#include "chrome/test/base/testing_browser_process.h"
+#include "chrome/test/base/testing_profile.h"
+#include "components/prefs/pref_service.h"
+#include "content/public/test/test_browser_thread_bundle.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace arc {
+
+class ArcTermsOfServiceNegotiatorTest : public testing::Test {
+ public:
+  ArcTermsOfServiceNegotiatorTest() = default;
+  ~ArcTermsOfServiceNegotiatorTest() override = default;
+
+  void SetUp() override {
+    user_manager_enabler_ =
+        base::MakeUnique<chromeos::ScopedUserManagerEnabler>(
+            new chromeos::FakeChromeUserManager());
+
+    profile_ = base::MakeUnique<TestingProfile>();
+    profile_->GetPrefs()->SetBoolean(prefs::kArcBackupRestoreEnabled, false);
+    profile_->GetPrefs()->SetBoolean(prefs::kArcLocationServiceEnabled, false);
+
+    support_host_ = base::MakeUnique<ArcSupportHost>(profile_.get());
+    fake_arc_support_ = base::MakeUnique<FakeArcSupport>(support_host_.get());
+    negotiator_ = base::MakeUnique<ArcTermsOfServiceNegotiator>(
+        profile_->GetPrefs(), support_host());
+  }
+
+  void TearDown() override {
+    negotiator_.reset();
+    fake_arc_support_.reset();
+    support_host_.reset();
+    profile_.reset();
+    user_manager_enabler_.reset();
+  }
+
+  Profile* profile() { return profile_.get(); }
+  ArcSupportHost* support_host() { return support_host_.get(); }
+  FakeArcSupport* fake_arc_support() { return fake_arc_support_.get(); }
+  ArcTermsOfServiceNegotiator* negotiator() { return negotiator_.get(); }
+
+ private:
+  // Fake as if the current testing thread is UI thread.
+  content::TestBrowserThreadBundle bundle_;
+
+  std::unique_ptr<TestingProfile> profile_;
+  std::unique_ptr<chromeos::ScopedUserManagerEnabler> user_manager_enabler_;
+  std::unique_ptr<ArcSupportHost> support_host_;
+  std::unique_ptr<FakeArcSupport> fake_arc_support_;
+  std::unique_ptr<ArcTermsOfServiceNegotiator> negotiator_;
+
+  DISALLOW_COPY_AND_ASSIGN(ArcTermsOfServiceNegotiatorTest);
+};
+
+namespace {
+
+enum class Status {
+  PENDING,
+  ACCEPTED,
+  CANCELLED,
+};
+
+// For better logging.
+std::ostream& operator<<(std::ostream& os, Status status) {
+  switch (status) {
+    case Status::PENDING:
+      return os << "PENDING";
+    case Status::ACCEPTED:
+      return os << "ACCEPTED";
+    case Status::CANCELLED:
+      return os << "CANCELLED";
+  }
+
+  NOTREACHED();
+  return os;
+}
+
+ArcTermsOfServiceNegotiator::NegotiationCallback UpdateStatusCallback(
+    Status* status) {
+  return base::Bind(
+      [](Status* status, bool accepted) {
+        *status = accepted ? Status::ACCEPTED : Status::CANCELLED;
+      },
+      status);
+}
+
+}  // namespace
+
+TEST_F(ArcTermsOfServiceNegotiatorTest, Accept) {
+  // Show Terms of service page.
+  Status status = Status::PENDING;
+  negotiator()->StartNegotiation(UpdateStatusCallback(&status));
+
+  // TERMS page should be shown.
+  EXPECT_EQ(status, Status::PENDING);
+  EXPECT_EQ(fake_arc_support()->ui_page(), ArcSupportHost::UIPage::TERMS);
+
+  // Check the preference related checkbox.
+  fake_arc_support()->set_metrics_mode(true);
+  fake_arc_support()->set_backup_and_restore_mode(true);
+  fake_arc_support()->set_location_service_mode(true);
+
+  // Make sure preference values are not yet updated.
+  EXPECT_FALSE(
+      profile()->GetPrefs()->GetBoolean(prefs::kArcBackupRestoreEnabled));
+  EXPECT_FALSE(
+      profile()->GetPrefs()->GetBoolean(prefs::kArcLocationServiceEnabled));
+
+  // Click the "AGREE" button so that the callback should be invoked
+  // with |agreed| = true.
+  fake_arc_support()->ClickAgreeButton();
+  EXPECT_EQ(status, Status::ACCEPTED);
+
+  // Make sure preference values are now updated.
+  EXPECT_TRUE(
+      profile()->GetPrefs()->GetBoolean(prefs::kArcBackupRestoreEnabled));
+  EXPECT_TRUE(
+      profile()->GetPrefs()->GetBoolean(prefs::kArcLocationServiceEnabled));
+}
+
+TEST_F(ArcTermsOfServiceNegotiatorTest, Cancel) {
+  // Show Terms of service page.
+  Status status = Status::PENDING;
+  negotiator()->StartNegotiation(UpdateStatusCallback(&status));
+
+  // TERMS page should be shown.
+  EXPECT_EQ(status, Status::PENDING);
+  EXPECT_EQ(fake_arc_support()->ui_page(), ArcSupportHost::UIPage::TERMS);
+
+  // Check the preference related checkbox.
+  fake_arc_support()->set_metrics_mode(true);
+  fake_arc_support()->set_backup_and_restore_mode(true);
+  fake_arc_support()->set_location_service_mode(true);
+
+  // Make sure preference values are not yet updated.
+  EXPECT_FALSE(
+      profile()->GetPrefs()->GetBoolean(prefs::kArcBackupRestoreEnabled));
+  EXPECT_FALSE(
+      profile()->GetPrefs()->GetBoolean(prefs::kArcLocationServiceEnabled));
+
+  // Clicking "CANCEL" button closes the window.
+  fake_arc_support()->Close();
+  EXPECT_EQ(status, Status::CANCELLED);
+
+  // Make sure preference checkbox values are discarded.
+  EXPECT_FALSE(
+      profile()->GetPrefs()->GetBoolean(prefs::kArcBackupRestoreEnabled));
+  EXPECT_FALSE(
+      profile()->GetPrefs()->GetBoolean(prefs::kArcLocationServiceEnabled));
+}
+
+TEST_F(ArcTermsOfServiceNegotiatorTest, Retry) {
+  // Show Terms of service page.
+  Status status = Status::PENDING;
+  negotiator()->StartNegotiation(UpdateStatusCallback(&status));
+
+  // TERMS page should be shown.
+  EXPECT_EQ(status, Status::PENDING);
+  EXPECT_EQ(fake_arc_support()->ui_page(), ArcSupportHost::UIPage::TERMS);
+
+  // Switch to error page.
+  support_host()->ShowError(ArcSupportHost::Error::SIGN_IN_NETWORK_ERROR,
+                            false);
+
+  // The callback should not be called yet.
+  EXPECT_EQ(status, Status::PENDING);
+  EXPECT_EQ(fake_arc_support()->ui_page(), ArcSupportHost::UIPage::ERROR);
+
+  // Click RETRY button on the page, then Terms of service page should be
+  // re-shown.
+  fake_arc_support()->ClickRetryButton();
+  EXPECT_EQ(status, Status::PENDING);
+  EXPECT_EQ(fake_arc_support()->ui_page(), ArcSupportHost::UIPage::TERMS);
+}
+
+}  // namespace arc
diff --git a/chrome/browser/chromeos/file_manager/zip_file_creator_browsertest.cc b/chrome/browser/chromeos/file_manager/zip_file_creator_browsertest.cc
index ab2fecf..29c46fad 100644
--- a/chrome/browser/chromeos/file_manager/zip_file_creator_browsertest.cc
+++ b/chrome/browser/chromeos/file_manager/zip_file_creator_browsertest.cc
@@ -54,11 +54,10 @@
   std::vector<base::FilePath> paths;
   paths.push_back(base::FilePath(FILE_PATH_LITERAL("not.exist")));
   (new ZipFileCreator(
-       base::Bind(
-           &TestCallback, &success, content::GetQuitTaskForRunLoop(&run_loop)),
-       zip_base_dir(),
-       paths,
-       zip_archive_path()))->Start();
+       base::Bind(&TestCallback, &success,
+                  content::GetDeferredQuitTaskForRunLoop(&run_loop)),
+       zip_base_dir(), paths, zip_archive_path()))
+      ->Start();
 
   content::RunThisRunLoop(&run_loop);
   EXPECT_FALSE(success);
@@ -84,11 +83,10 @@
   paths.push_back(kFile1);
   paths.push_back(kFile2);
   (new ZipFileCreator(
-       base::Bind(
-           &TestCallback, &success, content::GetQuitTaskForRunLoop(&run_loop)),
-       zip_base_dir(),
-       paths,
-       zip_archive_path()))->Start();
+       base::Bind(&TestCallback, &success,
+                  content::GetDeferredQuitTaskForRunLoop(&run_loop)),
+       zip_base_dir(), paths, zip_archive_path()))
+      ->Start();
 
   content::RunThisRunLoop(&run_loop);
   EXPECT_TRUE(success);
diff --git a/chrome/browser/chromeos/login/enrollment/enterprise_enrollment_helper_impl.cc b/chrome/browser/chromeos/login/enrollment/enterprise_enrollment_helper_impl.cc
index 051ec92..4d12d48 100644
--- a/chrome/browser/chromeos/login/enrollment/enterprise_enrollment_helper_impl.cc
+++ b/chrome/browser/chromeos/login/enrollment/enterprise_enrollment_helper_impl.cc
@@ -421,6 +421,9 @@
     case policy::EnrollmentStatus::STATUS_NO_MACHINE_IDENTIFICATION:
       UMA(policy::kMetricEnrollmentNoDeviceIdentification);
       break;
+    case policy::EnrollmentStatus::STATUS_ACTIVE_DIRECTORY_POLICY_FETCH_FAILED:
+      UMA(policy::kMetricEnrollmentActiveDirectoryPolicyFetchFailed);
+      break;
   }
 }
 
diff --git a/chrome/browser/chromeos/policy/enrollment_handler_chromeos.cc b/chrome/browser/chromeos/policy/enrollment_handler_chromeos.cc
index 3338b0d..02c3c067 100644
--- a/chrome/browser/chromeos/policy/enrollment_handler_chromeos.cc
+++ b/chrome/browser/chromeos/policy/enrollment_handler_chromeos.cc
@@ -25,6 +25,8 @@
 #include "chrome/browser/profiles/profile.h"
 #include "chromeos/attestation/attestation_flow.h"
 #include "chromeos/chromeos_switches.h"
+#include "chromeos/dbus/auth_policy_client.h"
+#include "chromeos/dbus/dbus_thread_manager.h"
 #include "google_apis/gaia/gaia_auth_util.h"
 #include "google_apis/gaia/gaia_urls.h"
 #include "net/http/http_status_code.h"
@@ -250,6 +252,7 @@
     // enterprise-managed.
     return;
   }
+  LOG(ERROR) << "Error in device policy store.";
   ReportResult(EnrollmentStatus::ForStoreError(store_->status(),
                                                store_->validation_status()));
 }
@@ -488,14 +491,38 @@
     return;
   }
 
+  SetStep(STEP_STORE_POLICY);
   if (device_mode_ == policy::DEVICE_MODE_ENTERPRISE_AD) {
-    ReportResult(EnrollmentStatus::ForStatus(EnrollmentStatus::STATUS_SUCCESS));
+    CHECK(install_attributes_->IsActiveDirectoryManaged());
+    // Update device settings so that in case of Active Directory unsigned
+    // policy is accepted.
+    chromeos::DeviceSettingsService::Get()->SetDeviceMode(
+        install_attributes_->GetMode());
+    chromeos::DBusThreadManager::Get()
+        ->GetAuthPolicyClient()
+        ->RefreshDevicePolicy(base::Bind(
+            &EnrollmentHandlerChromeOS::HandleActiveDirectoryPolicyRefreshed,
+            weak_ptr_factory_.GetWeakPtr()));
   } else {
-    SetStep(STEP_STORE_POLICY);
     store_->InstallInitialPolicy(*policy_);
   }
 }
 
+void EnrollmentHandlerChromeOS::HandleActiveDirectoryPolicyRefreshed(
+    bool success) {
+  DCHECK_EQ(STEP_STORE_POLICY, enrollment_step_);
+
+  if (!success) {
+    LOG(ERROR) << "Failed to load Active Directory policy.";
+    ReportResult(EnrollmentStatus::ForStatus(
+        EnrollmentStatus::STATUS_ACTIVE_DIRECTORY_POLICY_FETCH_FAILED));
+    return;
+  }
+
+  // After that, the enrollment flow continues in one of the OnStore* observers.
+  store_->Load();
+}
+
 void EnrollmentHandlerChromeOS::Stop() {
   if (client_.get())
     client_->RemoveObserver(this);
diff --git a/chrome/browser/chromeos/policy/enrollment_handler_chromeos.h b/chrome/browser/chromeos/policy/enrollment_handler_chromeos.h
index 7d61578..7d63d22 100644
--- a/chrome/browser/chromeos/policy/enrollment_handler_chromeos.h
+++ b/chrome/browser/chromeos/policy/enrollment_handler_chromeos.h
@@ -113,7 +113,8 @@
     STEP_LOCK_DEVICE = 8,         // Writing installation-time attributes.
     STEP_STORE_TOKEN_AND_ID = 9,  // Storing DM token and virtual device ID.
     STEP_STORE_ROBOT_AUTH = 10,   // Encrypting & writing robot refresh token.
-    STEP_STORE_POLICY = 11,       // Storing policy and API refresh token.
+    STEP_STORE_POLICY = 11,       // Storing policy and API refresh token. For
+                                  // AD, includes policy fetch via authpolicyd.
     STEP_FINISHED = 12,           // Enrollment process done, no further action.
   };
 
@@ -154,6 +155,9 @@
   // Handles completion of the robot token store operation.
   void HandleStoreRobotAuthTokenResult(bool result);
 
+  // Handles result from device policy refresh via authpolicyd.
+  void HandleActiveDirectoryPolicyRefreshed(bool success);
+
   // Drops any ongoing actions.
   void Stop();
 
diff --git a/chrome/browser/chromeos/policy/enrollment_status_chromeos.h b/chrome/browser/chromeos/policy/enrollment_status_chromeos.h
index b437347..4930f38 100644
--- a/chrome/browser/chromeos/policy/enrollment_status_chromeos.h
+++ b/chrome/browser/chromeos/policy/enrollment_status_chromeos.h
@@ -43,6 +43,9 @@
     STATUS_REGISTRATION_CERTIFICATE_FETCH_FAILED = 15,  // Cannot obtain
                                                         // registration cert.
     STATUS_NO_MACHINE_IDENTIFICATION = 16,  // Machine model or serial missing.
+    STATUS_ACTIVE_DIRECTORY_POLICY_FETCH_FAILED = 17,  // Failed to fetch Active
+                                                       // Directory policy via
+                                                       // authpolicyd.
   };
 
   // Helpers for constructing errors for relevant cases.
diff --git a/chrome/browser/chromeos/settings/device_settings_service.cc b/chrome/browser/chromeos/settings/device_settings_service.cc
index d96df94..73cd756 100644
--- a/chrome/browser/chromeos/settings/device_settings_service.cc
+++ b/chrome/browser/chromeos/settings/device_settings_service.cc
@@ -132,6 +132,8 @@
 void DeviceSettingsService::Store(
     std::unique_ptr<em::PolicyFetchResponse> policy,
     const base::Closure& callback) {
+  // On Active Directory managed devices policy is written only by authpolicyd.
+  CHECK(device_mode_ != policy::DEVICE_MODE_ENTERPRISE_AD);
   Enqueue(linked_ptr<SessionManagerOperation>(new StoreSettingsOperation(
       base::Bind(&DeviceSettingsService::HandleCompletedOperation,
                  weak_factory_.GetWeakPtr(), callback),
@@ -256,9 +258,6 @@
     const base::Closure& callback,
     SessionManagerOperation* operation,
     Status status) {
-  // Exactly one must be true: Active Directory management or existence of key.
-  DCHECK((device_mode_ == policy::DEVICE_MODE_ENTERPRISE_AD) !=
-         (operation->public_key() != nullptr));
   DCHECK_EQ(operation, pending_operations_.front().get());
 
   store_status_ = status;
diff --git a/chrome/browser/global_keyboard_shortcuts_mac_browsertest.mm b/chrome/browser/global_keyboard_shortcuts_mac_browsertest.mm
index 3e6b7f2d..1f69ccd 100644
--- a/chrome/browser/global_keyboard_shortcuts_mac_browsertest.mm
+++ b/chrome/browser/global_keyboard_shortcuts_mac_browsertest.mm
@@ -18,6 +18,20 @@
 
 using GlobalKeyboardShortcutsTest = ExtensionBrowserTest;
 
+namespace {
+
+void ActivateAccelerator(NSWindow* window, NSEvent* ns_event) {
+  if ([window performKeyEquivalent:ns_event])
+    return;
+
+  // This is consistent with the way AppKit dispatches events when
+  // -performKeyEquivalent: returns NO. See "The Path of Key Events" in the
+  // Cocoa Event Architecture documentation.
+  [window sendEvent:ns_event];
+}
+
+}  // namespace
+
 // Test that global keyboard shortcuts are handled by the native window.
 IN_PROC_BROWSER_TEST_F(GlobalKeyboardShortcutsTest, SwitchTabsMac) {
   NSWindow* ns_window = browser()->window()->GetNativeWindow();
@@ -29,17 +43,19 @@
   EXPECT_TRUE(tab_strip->IsTabSelected(1));
 
   // Ctrl+Tab goes to the next tab, which loops back to the first tab.
-  [ns_window performKeyEquivalent:SynthesizeKeyEvent(
-      ns_window, true, ui::VKEY_TAB, NSControlKeyMask)];
+  ActivateAccelerator(
+      ns_window,
+      SynthesizeKeyEvent(ns_window, true, ui::VKEY_TAB, NSControlKeyMask));
   EXPECT_TRUE(tab_strip->IsTabSelected(0));
 
   // Cmd+2 goes to the second tab.
-  [ns_window performKeyEquivalent:SynthesizeKeyEvent(
-      ns_window, true, ui::VKEY_2, NSCommandKeyMask)];
+  ActivateAccelerator(ns_window, SynthesizeKeyEvent(ns_window, true, ui::VKEY_2,
+                                                    NSCommandKeyMask));
   EXPECT_TRUE(tab_strip->IsTabSelected(1));
 
   // Cmd+{ goes to the previous tab.
-  [ns_window performKeyEquivalent:SynthesizeKeyEvent(
-      ns_window, true, ui::VKEY_OEM_4, NSShiftKeyMask | NSCommandKeyMask)];
+  ActivateAccelerator(ns_window,
+                      SynthesizeKeyEvent(ns_window, true, ui::VKEY_OEM_4,
+                                         NSShiftKeyMask | NSCommandKeyMask));
   EXPECT_TRUE(tab_strip->IsTabSelected(0));
 }
diff --git a/chrome/browser/media/webrtc/webrtc_text_log_handler.cc b/chrome/browser/media/webrtc/webrtc_text_log_handler.cc
index 18547fa..ac58ac3f 100644
--- a/chrome/browser/media/webrtc/webrtc_text_log_handler.cc
+++ b/chrome/browser/media/webrtc/webrtc_text_log_handler.cc
@@ -24,6 +24,7 @@
 #include "content/public/browser/gpu_data_manager.h"
 #include "content/public/browser/render_process_host.h"
 #include "gpu/config/gpu_info.h"
+#include "media/audio/audio_manager.h"
 #include "net/base/ip_address.h"
 #include "net/base/network_change_notifier.h"
 #include "net/base/network_interfaces.h"
@@ -474,6 +475,13 @@
                       ", gl-renderer=" + gpu_info.gl_renderer +
                       ", gl-version=" + gpu_info.gl_version);
 
+  // Audio manager
+  // On some platforms, this can vary depending on build flags and failure
+  // fallbacks. On Linux for example, we fallback on ALSA if PulseAudio fails to
+  // initialize.
+  LogToCircularBuffer(base::StringPrintf(
+      "Audio manager: %s", media::AudioManager::Get()->GetName()));
+
   // Network interfaces
   LogToCircularBuffer("Discovered " + base::SizeTToString(network_list.size()) +
                       " network interfaces:");
diff --git a/chrome/browser/policy/policy_browsertest.cc b/chrome/browser/policy/policy_browsertest.cc
index 2ceb570..d89f788 100644
--- a/chrome/browser/policy/policy_browsertest.cc
+++ b/chrome/browser/policy/policy_browsertest.cc
@@ -3956,6 +3956,8 @@
     arc::ArcSessionManager::DisableUIForTesting();
 
     browser()->profile()->GetPrefs()->SetBoolean(prefs::kArcSignedIn, true);
+    browser()->profile()->GetPrefs()->SetBoolean(prefs::kArcTermsAccepted,
+                                                 true);
   }
 
   void TearDownTest() { arc::ArcSessionManager::Get()->Shutdown(); }
diff --git a/chrome/browser/resources/settings/passwords_and_forms_page/passwords_section.html b/chrome/browser/resources/settings/passwords_and_forms_page/passwords_section.html
index 0fe8c28..9aa5ecf 100644
--- a/chrome/browser/resources/settings/passwords_and_forms_page/passwords_section.html
+++ b/chrome/browser/resources/settings/passwords_and_forms_page/passwords_section.html
@@ -23,8 +23,17 @@
         width: 0;
       }
 
+      /* The following non-flex directives allow eliding long originUrls from
+       * the left. Forcing rtl should not cause an issue for right-to-left
+       * languages in this case, since valid URL characters are restricted to
+       * ASCII. */
       .website-column {
+        direction: rtl;
         flex: 3;
+        overflow: hidden;
+        text-align: left;
+        text-overflow: ellipsis;
+        white-space: nowrap;
       }
 
       .username-column {
diff --git a/chrome/browser/sync/test/integration/dictionary_helper.cc b/chrome/browser/sync/test/integration/dictionary_helper.cc
index 30f92967..e6fd2914 100644
--- a/chrome/browser/sync/test/integration/dictionary_helper.cc
+++ b/chrome/browser/sync/test/integration/dictionary_helper.cc
@@ -56,7 +56,8 @@
   if (dictionary->IsLoaded())
     return;
   base::RunLoop run_loop;
-  DictionaryLoadObserver observer(content::GetQuitTaskForRunLoop(&run_loop));
+  DictionaryLoadObserver observer(
+      content::GetDeferredQuitTaskForRunLoop(&run_loop));
   dictionary->AddObserver(&observer);
   dictionary->Load();
   content::RunThisRunLoop(&run_loop);
diff --git a/chrome/browser/sync_file_system/sync_file_system_service_unittest.cc b/chrome/browser/sync_file_system/sync_file_system_service_unittest.cc
index c4d0035..8475219 100644
--- a/chrome/browser/sync_file_system/sync_file_system_service_unittest.cc
+++ b/chrome/browser/sync_file_system/sync_file_system_service_unittest.cc
@@ -73,12 +73,11 @@
   run_loop->Quit();
 }
 
-// This is called on IO thread.
-void VerifyFileError(base::RunLoop* run_loop,
+// This is called on IO thread. Posts |callback| to be called on UI thread.
+void VerifyFileError(base::Closure callback,
                      base::File::Error error) {
-  DCHECK(run_loop);
   EXPECT_EQ(base::File::FILE_OK, error);
-  run_loop->Quit();
+  BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, callback);
 }
 
 }  // namespace
@@ -430,7 +429,7 @@
       base::Bind(&CannedSyncableFileSystem::DoCreateFile,
                  base::Unretained(file_system_.get()),
                  kFile, base::Bind(&VerifyFileError,
-                                   &verify_file_error_run_loop)));
+                                   verify_file_error_run_loop.QuitClosure())));
 
   run_loop.Run();
 
diff --git a/chrome/browser/ui/views/ash/tab_scrubber_browsertest.cc b/chrome/browser/ui/views/ash/tab_scrubber_browsertest.cc
index 820ab2c..069af32 100644
--- a/chrome/browser/ui/views/ash/tab_scrubber_browsertest.cc
+++ b/chrome/browser/ui/views/ash/tab_scrubber_browsertest.cc
@@ -213,7 +213,7 @@
  private:
   void RunUntilTabActive(Browser* browser, int target) {
     base::RunLoop run_loop;
-    quit_closure_ = content::GetQuitTaskForRunLoop(&run_loop);
+    quit_closure_ = content::GetDeferredQuitTaskForRunLoop(&run_loop);
     browser->tab_strip_model()->AddObserver(this);
     target_index_ = target;
     content::RunThisRunLoop(&run_loop);
diff --git a/chrome/browser/ui/webui/chromeos/login/enrollment_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/enrollment_screen_handler.cc
index 4f2bcd5e..6741c32c 100644
--- a/chrome/browser/ui/webui/chromeos/login/enrollment_screen_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/enrollment_screen_handler.cc
@@ -382,6 +382,10 @@
       ShowError(IDS_ENTERPRISE_ENROLLMENT_STATUS_NO_MACHINE_IDENTIFICATION,
                 false);
       return;
+    case policy::EnrollmentStatus::STATUS_ACTIVE_DIRECTORY_POLICY_FETCH_FAILED:
+      ShowError(IDS_ENTERPRISE_ENROLLMENT_ERROR_ACTIVE_DIRECTORY_POLICY_FETCH,
+                false);
+      return;
   }
   NOTREACHED();
 }
diff --git a/chrome/test/base/testing_profile.cc b/chrome/test/base/testing_profile.cc
index f2c32ae..d175997 100644
--- a/chrome/test/base/testing_profile.cc
+++ b/chrome/test/base/testing_profile.cc
@@ -651,7 +651,7 @@
     return;
   base::RunLoop run_loop;
   HistoryIndexRestoreObserver observer(
-      content::GetQuitTaskForRunLoop(&run_loop));
+      content::GetDeferredQuitTaskForRunLoop(&run_loop));
   index->set_restore_cache_observer(&observer);
   run_loop.Run();
   index->set_restore_cache_observer(NULL);
diff --git a/chromecast/media/audio/cast_audio_manager.cc b/chromecast/media/audio/cast_audio_manager.cc
index 230a1f9..fbad984 100644
--- a/chromecast/media/audio/cast_audio_manager.cc
+++ b/chromecast/media/audio/cast_audio_manager.cc
@@ -83,6 +83,10 @@
       ::media::CHANNEL_LAYOUT_STEREO, 48000, 16, 1024);
 }
 
+const char* CastAudioManager::GetName() {
+  return "Cast";
+}
+
 std::unique_ptr<MediaPipelineBackend>
 CastAudioManager::CreateMediaPipelineBackend(
     const MediaPipelineDeviceParams& params) {
diff --git a/chromecast/media/audio/cast_audio_manager.h b/chromecast/media/audio/cast_audio_manager.h
index f9a733e..677954ea 100644
--- a/chromecast/media/audio/cast_audio_manager.h
+++ b/chromecast/media/audio/cast_audio_manager.h
@@ -39,6 +39,7 @@
       ::media::AudioDeviceNames* device_names) override;
   ::media::AudioParameters GetInputStreamParameters(
       const std::string& device_id) override;
+  const char* GetName() override;
 
   // AudioManagerBase implementation
   void ReleaseOutputStream(::media::AudioOutputStream* stream) override;
diff --git a/components/policy/core/common/cloud/enterprise_metrics.h b/components/policy/core/common/cloud/enterprise_metrics.h
index 7d84783..7f8427be 100644
--- a/components/policy/core/common/cloud/enterprise_metrics.h
+++ b/components/policy/core/common/cloud/enterprise_metrics.h
@@ -226,6 +226,8 @@
   kMetricEnrollmentRegisterCannotSignRequest = 53,
   // Device model or serial number missing from VPD.
   kMetricEnrollmentNoDeviceIdentification = 54,
+  // Active Directory policy fetch failed.
+  kMetricEnrollmentActiveDirectoryPolicyFetchFailed = 55,
 };
 
 // Events related to policy refresh.
diff --git a/components/policy/core/common/schema_map.cc b/components/policy/core/common/schema_map.cc
index 90d62c56..dd2a329 100644
--- a/components/policy/core/common/schema_map.cc
+++ b/components/policy/core/common/schema_map.cc
@@ -70,10 +70,10 @@
                                   SCHEMA_STRICT,
                                   &error_path,
                                   &error)) {
-        LOG(ERROR) << "Dropping policy " << policy_name << " for "
-                   << it->first.component_id
-                   << " because it's not valid: " << error
-                   << " at " << error_path;
+        LOG(ERROR) << "Dropping policy " << policy_name << " of component "
+                   << it->first.component_id << " due to error at "
+                   << (error_path.empty() ? "root" : error_path) << ": "
+                   << error;
         map->Erase(policy_name);
       }
     }
diff --git a/content/browser/loader/async_revalidation_manager_browsertest.cc b/content/browser/loader/async_revalidation_manager_browsertest.cc
index 2646222..2a9b8c33 100644
--- a/content/browser/loader/async_revalidation_manager_browsertest.cc
+++ b/content/browser/loader/async_revalidation_manager_browsertest.cc
@@ -90,8 +90,10 @@
 
     // The second time this handler is run is the async revalidation. Tests can
     // use this for synchronisation.
-    if (version == 2)
-      run_loop_.Quit();
+    if (version == 2) {
+      BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
+                              run_loop_.QuitClosure());
+    }
     return std::move(http_response);
   }
 
diff --git a/content/public/test/test_launcher.h b/content/public/test/test_launcher.h
index 522c5fd..b58f9b75d 100644
--- a/content/public/test/test_launcher.h
+++ b/content/public/test/test_launcher.h
@@ -14,7 +14,6 @@
 namespace base {
 class CommandLine;
 class FilePath;
-class RunLoop;
 }
 
 namespace content {
@@ -47,8 +46,6 @@
   virtual bool AdjustChildProcessCommandLine(
       base::CommandLine* command_line,
       const base::FilePath& temp_data_dir) = 0;
-  virtual void PreRunMessageLoop(base::RunLoop* run_loop) {}
-  virtual void PostRunMessageLoop() {}
   virtual ContentMainDelegate* CreateContentMainDelegate() = 0;
 
   // Called prior to running each test. The delegate may alter the CommandLine
diff --git a/content/public/test/test_utils.cc b/content/public/test/test_utils.cc
index a19a31d..4c6449d 100644
--- a/content/public/test/test_utils.cc
+++ b/content/public/test/test_utils.cc
@@ -120,23 +120,14 @@
 void RunThisRunLoop(base::RunLoop* run_loop) {
   base::MessageLoop::ScopedNestableTaskAllower allow(
       base::MessageLoop::current());
-
-  // If we're running inside a browser test, we might need to allow the test
-  // launcher to do extra work before/after running a nested message loop.
-  TestLauncherDelegate* delegate = NULL;
-  delegate = GetCurrentTestLauncherDelegate();
-  if (delegate)
-    delegate->PreRunMessageLoop(run_loop);
   run_loop->Run();
-  if (delegate)
-    delegate->PostRunMessageLoop();
 }
 
 void RunAllPendingInMessageLoop() {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   base::RunLoop run_loop;
   base::ThreadTaskRunnerHandle::Get()->PostTask(
-      FROM_HERE, GetQuitTaskForRunLoop(&run_loop));
+      FROM_HERE, GetDeferredQuitTaskForRunLoop(&run_loop));
   RunThisRunLoop(&run_loop);
 }
 
@@ -175,7 +166,7 @@
   }
 }
 
-base::Closure GetQuitTaskForRunLoop(base::RunLoop* run_loop) {
+base::Closure GetDeferredQuitTaskForRunLoop(base::RunLoop* run_loop) {
   return base::Bind(&DeferredQuitRunLoop, run_loop->QuitClosure(),
                     kNumQuitDeferrals);
 }
@@ -240,7 +231,7 @@
   if (loop_running_) {
     switch (quit_mode_) {
       case QuitMode::DEFERRED:
-        GetQuitTaskForRunLoop(&run_loop_).Run();
+        GetDeferredQuitTaskForRunLoop(&run_loop_).Run();
         break;
       case QuitMode::IMMEDIATE:
         run_loop_.Quit();
diff --git a/content/public/test/test_utils.h b/content/public/test/test_utils.h
index e6bbc562..6e46fd2 100644
--- a/content/public/test/test_utils.h
+++ b/content/public/test/test_utils.h
@@ -62,7 +62,7 @@
 
 // Get task to quit the given RunLoop. It allows a few generations of pending
 // tasks to run as opposed to run_loop->QuitClosure().
-base::Closure GetQuitTaskForRunLoop(base::RunLoop* run_loop);
+base::Closure GetDeferredQuitTaskForRunLoop(base::RunLoop* run_loop);
 
 // Executes the specified JavaScript in the specified frame, and runs a nested
 // MessageLoop. When the result is available, it is returned.
@@ -91,6 +91,12 @@
 // has returned is safe and has no effect.
 // Note that by default Quit does not quit immediately. If that is not what you
 // really need, pass QuitMode::IMMEDIATE in the constructor.
+//
+// DEPRECATED. Consider using base::RunLoop, in most cases MessageLoopRunner is
+// not needed.  If you need to defer quitting the loop, use
+// GetDeferredQuitTaskForRunLoop directly.
+// If you found a case where base::RunLoop is inconvenient or can not be used at
+// all, please post details in a comment on https://crbug.com/668707.
 class MessageLoopRunner : public base::RefCounted<MessageLoopRunner> {
  public:
   enum class QuitMode {
diff --git a/content/renderer/media/gpu/rtc_video_decoder.cc b/content/renderer/media/gpu/rtc_video_decoder.cc
index 34100350..929ab57 100644
--- a/content/renderer/media/gpu/rtc_video_decoder.cc
+++ b/content/renderer/media/gpu/rtc_video_decoder.cc
@@ -210,10 +210,10 @@
 #endif
 
   bool need_to_reset_for_midstream_resize = false;
-  if (inputImage._frameType == webrtc::kVideoFrameKey) {
-    const gfx::Size new_frame_size(inputImage._encodedWidth,
-                                   inputImage._encodedHeight);
-    DVLOG(2) << "Got key frame. size=" << new_frame_size.ToString();
+  const gfx::Size new_frame_size(inputImage._encodedWidth,
+                                 inputImage._encodedHeight);
+  if (!new_frame_size.IsEmpty() && new_frame_size != frame_size_) {
+    DVLOG(2) << "Got new size=" << new_frame_size.ToString();
 
     if (new_frame_size.width() > max_resolution_.width() ||
         new_frame_size.width() < min_resolution_.width() ||
@@ -237,7 +237,7 @@
     // If we're are in an error condition, increase the counter.
     vda_error_counter_ += vda_error_counter_ ? 1 : 0;
 
-    DVLOG(1) << "The first frame should be a key frame. Drop this.";
+    DVLOG(1) << "The first frame should have resolution. Drop this.";
     return WEBRTC_VIDEO_CODEC_ERROR;
   }
 
diff --git a/content/renderer/media/gpu/rtc_video_decoder_unittest.cc b/content/renderer/media/gpu/rtc_video_decoder_unittest.cc
index 877d457..7fdbb91 100644
--- a/content/renderer/media/gpu/rtc_video_decoder_unittest.cc
+++ b/content/renderer/media/gpu/rtc_video_decoder_unittest.cc
@@ -291,8 +291,8 @@
 
   webrtc::EncodedImage input_image;
   input_image._completeFrame = true;
-  input_image._encodedWidth = kMinResolutionWidth;
-  input_image._encodedHeight = kMaxResolutionHeight;
+  input_image._encodedWidth = 0;
+  input_image._encodedHeight = 0;
   input_image._frameType = webrtc::kVideoFrameDelta;
   input_image._length = kMinResolutionWidth * kMaxResolutionHeight;
   EXPECT_EQ(WEBRTC_VIDEO_CODEC_ERROR,
@@ -310,8 +310,8 @@
             rtc_decoder_->Decode(input_image, false, nullptr, nullptr, 0));
   EXPECT_EQ(1, rtc_decoder_->GetVDAErrorCounterForTesting());
 
-  // Decoder expects a keyframe after reset, so drops any other frames. However,
-  // we should still increment the error counter.
+  // Decoder expects a frame with size after reset, so drops any other frames.
+  // However, we should still increment the error counter.
   EXPECT_EQ(WEBRTC_VIDEO_CODEC_ERROR,
             rtc_decoder_->Decode(input_image, false, nullptr, nullptr, 0));
   EXPECT_EQ(2, rtc_decoder_->GetVDAErrorCounterForTesting());
diff --git a/extensions/test/result_catcher.cc b/extensions/test/result_catcher.cc
index 53c569ff..f2e9801 100644
--- a/extensions/test/result_catcher.cc
+++ b/extensions/test/result_catcher.cc
@@ -30,7 +30,7 @@
   // empty.
   if (results_.empty()) {
     base::RunLoop run_loop;
-    quit_closure_ = content::GetQuitTaskForRunLoop(&run_loop);
+    quit_closure_ = content::GetDeferredQuitTaskForRunLoop(&run_loop);
     content::RunThisRunLoop(&run_loop);
     quit_closure_ = base::Closure();
   }
diff --git a/ios/chrome/browser/favicon/BUILD.gn b/ios/chrome/browser/favicon/BUILD.gn
index 162387ab..01b0c56 100644
--- a/ios/chrome/browser/favicon/BUILD.gn
+++ b/ios/chrome/browser/favicon/BUILD.gn
@@ -3,6 +3,7 @@
 # found in the LICENSE file.
 
 source_set("favicon") {
+  configs += [ "//build/config/compiler:enable_arc" ]
   sources = [
     "favicon_attributes.h",
     "favicon_attributes.mm",
diff --git a/ios/chrome/browser/favicon/favicon_attributes.mm b/ios/chrome/browser/favicon/favicon_attributes.mm
index b0b0050f..3659175 100644
--- a/ios/chrome/browser/favicon/favicon_attributes.mm
+++ b/ios/chrome/browser/favicon/favicon_attributes.mm
@@ -5,11 +5,12 @@
 #import "ios/chrome/browser/favicon/favicon_attributes.h"
 
 #include "base/logging.h"
-#include "base/mac/objc_property_releaser.h"
 
-@implementation FaviconAttributes {
-  base::mac::ObjCPropertyReleaser _propertyReleaser_FaviconAttributes;
-}
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+@implementation FaviconAttributes
 @synthesize faviconImage = _faviconImage;
 @synthesize monogramString = _monogramString;
 @synthesize textColor = _textColor;
@@ -22,11 +23,10 @@
   DCHECK(image || (monogram && textColor && backgroundColor));
   self = [super init];
   if (self) {
-    _propertyReleaser_FaviconAttributes.Init(self, [FaviconAttributes class]);
-    _faviconImage = [image retain];
+    _faviconImage = image;
     _monogramString = [monogram copy];
-    _textColor = [textColor retain];
-    _backgroundColor = [backgroundColor retain];
+    _textColor = textColor;
+    _backgroundColor = backgroundColor;
   }
 
   return self;
@@ -49,15 +49,15 @@
 }
 
 + (instancetype)attributesWithImage:(UIImage*)image {
-  return [[[self alloc] initWithImage:image] autorelease];
+  return [[self alloc] initWithImage:image];
 }
 
 + (instancetype)attributesWithMonogram:(NSString*)monogram
                              textColor:(UIColor*)textColor
                        backgroundColor:(UIColor*)backgroundColor {
-  return [[[self alloc] initWithMonogram:monogram
-                               textColor:textColor
-                         backgroundColor:backgroundColor] autorelease];
+  return [[self alloc] initWithMonogram:monogram
+                              textColor:textColor
+                        backgroundColor:backgroundColor];
 }
 
 @end
diff --git a/ios/chrome/browser/favicon/favicon_attributes_provider.mm b/ios/chrome/browser/favicon/favicon_attributes_provider.mm
index a417397..9e852cb6 100644
--- a/ios/chrome/browser/favicon/favicon_attributes_provider.mm
+++ b/ios/chrome/browser/favicon/favicon_attributes_provider.mm
@@ -16,6 +16,10 @@
 #include "skia/ext/skia_utils_ios.h"
 #include "url/gurl.h"
 
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
 @interface FaviconAttributesProvider () {
   // Used to cancel tasks for the LargeIconService.
   base::CancelableTaskTracker _faviconTaskTracker;
@@ -76,7 +80,7 @@
   CGFloat faviconSize = [UIScreen mainScreen].scale * self.faviconSize;
   CGFloat minFaviconSize = [UIScreen mainScreen].scale * self.minSize;
   self.largeIconService->GetLargeIconOrFallbackStyle(
-      URL, minFaviconSize, faviconSize, base::BindBlock(faviconBlock),
+      URL, minFaviconSize, faviconSize, base::BindBlockArc(faviconBlock),
       &_faviconTaskTracker);
 }
 @end
diff --git a/ios/chrome/browser/favicon/favicon_client_impl.mm b/ios/chrome/browser/favicon/favicon_client_impl.mm
index a35e4b27..860e4894 100644
--- a/ios/chrome/browser/favicon/favicon_client_impl.mm
+++ b/ios/chrome/browser/favicon/favicon_client_impl.mm
@@ -11,6 +11,10 @@
 #include "ios/public/provider/chrome/browser/chrome_browser_provider.h"
 #include "url/gurl.h"
 
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
 namespace {
 
 void RunFaviconCallbackIfNotCanceled(
diff --git a/ios/chrome/browser/favicon/favicon_loader.h b/ios/chrome/browser/favicon/favicon_loader.h
index 60f8ccc..ee8a9ba6 100644
--- a/ios/chrome/browser/favicon/favicon_loader.h
+++ b/ios/chrome/browser/favicon/favicon_loader.h
@@ -8,7 +8,6 @@
 #include <memory>
 #include <vector>
 
-#import "base/mac/scoped_nsobject.h"
 #include "base/macros.h"
 #include "base/task/cancelable_task_tracker.h"
 #include "base/threading/thread_checker.h"
@@ -69,7 +68,7 @@
   // Holds cached favicons. This dictionary is populated as favicons are
   // retrieved from the FaviconService. This will be emptied during low-memory
   // conditions. Keyed by NSString of URL spec.
-  base::scoped_nsobject<NSMutableDictionary> favicon_cache_;
+  NSMutableDictionary* favicon_cache_;
 
   DISALLOW_COPY_AND_ASSIGN(FaviconLoader);
 };
diff --git a/ios/chrome/browser/favicon/favicon_loader.mm b/ios/chrome/browser/favicon/favicon_loader.mm
index eb947b1..ccde02f8 100644
--- a/ios/chrome/browser/favicon/favicon_loader.mm
+++ b/ios/chrome/browser/favicon/favicon_loader.mm
@@ -14,20 +14,23 @@
 #include "ui/gfx/favicon_size.h"
 #include "url/gurl.h"
 
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
 struct FaviconLoader::RequestData {
   RequestData() {}
   RequestData(NSString* key, FaviconLoader::ImageCompletionBlock block)
-      : key([key copy]), block(block, base::scoped_policy::RETAIN) {}
+      : key([key copy]), block(block) {}
   ~RequestData() {}
 
-  base::scoped_nsobject<NSString> key;
+  NSString* key;
   base::mac::ScopedBlock<FaviconLoader::ImageCompletionBlock> block;
 };
 
 FaviconLoader::FaviconLoader(favicon::FaviconService* favicon_service)
     : favicon_service_(favicon_service),
-      favicon_cache_([[NSMutableDictionary dictionaryWithCapacity:10] retain]) {
-}
+      favicon_cache_([NSMutableDictionary dictionaryWithCapacity:10]) {}
 
 FaviconLoader::~FaviconLoader() {}
 
@@ -67,8 +70,7 @@
 void FaviconLoader::PurgeCache() {
   DCHECK(thread_checker_.CalledOnValidThread());
   cancelable_task_tracker_.TryCancelAll();
-  favicon_cache_.reset(
-      [[NSMutableDictionary dictionaryWithCapacity:10] retain]);
+  favicon_cache_ = [NSMutableDictionary dictionaryWithCapacity:10];
 }
 
 void FaviconLoader::OnFaviconAvailable(
diff --git a/ios/chrome/browser/favicon/ios_chrome_favicon_loader_factory.mm b/ios/chrome/browser/favicon/ios_chrome_favicon_loader_factory.mm
index 5b99726..c839d07a 100644
--- a/ios/chrome/browser/favicon/ios_chrome_favicon_loader_factory.mm
+++ b/ios/chrome/browser/favicon/ios_chrome_favicon_loader_factory.mm
@@ -13,6 +13,10 @@
 #import "ios/chrome/browser/favicon/favicon_loader.h"
 #include "ios/chrome/browser/favicon/favicon_service_factory.h"
 
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
 FaviconLoader* IOSChromeFaviconLoaderFactory::GetForBrowserState(
     ios::ChromeBrowserState* browser_state) {
   return static_cast<FaviconLoader*>(
diff --git a/ios/chrome/browser/reading_list/BUILD.gn b/ios/chrome/browser/reading_list/BUILD.gn
index 6a07d576..7c7148b 100644
--- a/ios/chrome/browser/reading_list/BUILD.gn
+++ b/ios/chrome/browser/reading_list/BUILD.gn
@@ -10,6 +10,8 @@
     "reading_list_download_service.h",
     "reading_list_download_service_factory.cc",
     "reading_list_download_service_factory.h",
+    "reading_list_entry_loading_util.h",
+    "reading_list_entry_loading_util.mm",
     "reading_list_model_factory.cc",
     "reading_list_model_factory.h",
     "reading_list_web_state_observer.h",
@@ -41,6 +43,7 @@
   testonly = true
   sources = [
     "offline_url_utils_unittest.cc",
+    "reading_list_entry_loading_util_unittest.mm",
     "url_downloader_unittest.mm",
   ]
   deps = [
@@ -50,7 +53,9 @@
     "//components/reading_list/ios",
     "//ios/chrome/browser",
     "//ios/chrome/browser/dom_distiller",
+    "//ios/web",
     "//ios/web:test_support",
+    "//net",
     "//testing/gtest",
     "//url",
   ]
diff --git a/ios/chrome/browser/reading_list/offline_url_utils.cc b/ios/chrome/browser/reading_list/offline_url_utils.cc
index f8b3086..b3d3037 100644
--- a/ios/chrome/browser/reading_list/offline_url_utils.cc
+++ b/ios/chrome/browser/reading_list/offline_url_utils.cc
@@ -8,14 +8,40 @@
 #include "base/strings/stringprintf.h"
 #include "components/reading_list/ios/offline_url_utils.h"
 #include "ios/chrome/browser/chrome_url_constants.h"
+#include "net/base/url_util.h"
+
+namespace {
+const char kVirtualURLQueryParam[] = "virtualURL";
+}
 
 namespace reading_list {
 
-GURL DistilledURLForPath(const base::FilePath& distilled_path) {
+GURL DistilledURLForPath(const base::FilePath& distilled_path,
+                         const GURL& virtual_url) {
   if (distilled_path.empty()) {
     return GURL();
   }
-  return GURL(kChromeUIOfflineURL + distilled_path.value());
+  GURL page_url(kChromeUIOfflineURL);
+  GURL::Replacements replacements;
+  replacements.SetPathStr(distilled_path.value());
+  page_url = page_url.ReplaceComponents(replacements);
+  if (virtual_url.is_valid()) {
+    page_url = net::AppendQueryParameter(page_url, kVirtualURLQueryParam,
+                                         virtual_url.spec());
+  }
+  return page_url;
+}
+
+GURL VirtualURLForDistilledURL(const GURL& distilled_url) {
+  std::string virtual_url_string;
+  if (net::GetValueForKeyInQuery(distilled_url, kVirtualURLQueryParam,
+                                 &virtual_url_string)) {
+    GURL virtual_url = GURL(virtual_url_string);
+    if (virtual_url.is_valid()) {
+      return virtual_url;
+    }
+  }
+  return distilled_url;
 }
 
 GURL FileURLForDistilledURL(const GURL& distilled_url,
diff --git a/ios/chrome/browser/reading_list/offline_url_utils.h b/ios/chrome/browser/reading_list/offline_url_utils.h
index c0997c7..bee8586 100644
--- a/ios/chrome/browser/reading_list/offline_url_utils.h
+++ b/ios/chrome/browser/reading_list/offline_url_utils.h
@@ -13,7 +13,11 @@
 namespace reading_list {
 
 // The distilled URL chrome://offline/... that will load the file at |path|.
-GURL DistilledURLForPath(const base::FilePath& path);
+GURL DistilledURLForPath(const base::FilePath& path, const GURL& virtual_url);
+
+// If |distilled_url| has a query "virtualURL" query params that is a URL,
+// returns it. If not, return |distilled_url|
+GURL VirtualURLForDistilledURL(const GURL& distilled_url);
 
 // The file URL pointing to the local file to load to display |distilled_url|.
 // If |resources_root_url| is not nullptr, it is set to a file URL to the
diff --git a/ios/chrome/browser/reading_list/offline_url_utils_unittest.cc b/ios/chrome/browser/reading_list/offline_url_utils_unittest.cc
index 9f68501..7beea10 100644
--- a/ios/chrome/browser/reading_list/offline_url_utils_unittest.cc
+++ b/ios/chrome/browser/reading_list/offline_url_utils_unittest.cc
@@ -13,10 +13,36 @@
 // Checks the distilled URL for the page is chrome://offline/MD5/page.html;
 TEST(OfflineURLUtilsTest, DistilledURLForPathTest) {
   base::FilePath page_path("MD5/page.html");
-  GURL distilled_url = reading_list::DistilledURLForPath(page_path);
+  GURL distilled_url = reading_list::DistilledURLForPath(page_path, GURL());
   EXPECT_EQ("chrome://offline/MD5/page.html", distilled_url.spec());
 }
 
+// Checks the distilled URL for the page with an onlineURL is
+// chrome://offline/MD5/page.html?virtualURL=encorded%20URL;
+TEST(OfflineURLUtilsTest, DistilledURLForPathWithVirtualURLTest) {
+  base::FilePath page_path("MD5/page.html");
+  GURL online_url = GURL("http://foo.bar");
+  GURL distilled_url = reading_list::DistilledURLForPath(page_path, online_url);
+  EXPECT_EQ("chrome://offline/MD5/page.html?virtualURL=http%3A%2F%2Ffoo.bar%2F",
+            distilled_url.spec());
+}
+
+// Checks the distilled URL for the page is chrome://offline/MD5/page.html;
+TEST(OfflineURLUtilsTest, VirtualURLForDistilledURLTest) {
+  GURL distilled_url("chrome://offline/MD5/page.html");
+  GURL virtual_url = reading_list::VirtualURLForDistilledURL(distilled_url);
+  EXPECT_EQ("chrome://offline/MD5/page.html", virtual_url.spec());
+}
+
+// Checks the distilled URL for the page with an onlineURL is
+// chrome://offline/MD5/page.html?virtualURL=encorded%20URL;
+TEST(OfflineURLUtilsTest, VirtualURLForDistilledURLWithVirtualURLTest) {
+  GURL distilled_url(
+      "chrome://offline/MD5/page.html?virtualURL=http%3A%2F%2Ffoo.bar%2F");
+  GURL virtual_url = reading_list::VirtualURLForDistilledURL(distilled_url);
+  EXPECT_EQ("http://foo.bar/", virtual_url.spec());
+}
+
 // Checks the file path for chrome://offline/MD5/page.html is
 // file://profile_path/Offline/MD5/page.html.
 // Checks the resource root for chrome://offline/MD5/page.html is
diff --git a/ios/chrome/browser/reading_list/reading_list_entry_loading_util.h b/ios/chrome/browser/reading_list/reading_list_entry_loading_util.h
new file mode 100644
index 0000000..0218cda
--- /dev/null
+++ b/ios/chrome/browser/reading_list/reading_list_entry_loading_util.h
@@ -0,0 +1,30 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IOS_CHROME_BROWSER_READING_LIST_READING_LIST_ENTRY_LOADING_UTIL_H_
+#define IOS_CHROME_BROWSER_READING_LIST_READING_LIST_ENTRY_LOADING_UTIL_H_
+
+class ReadingListEntry;
+class ReadingListModel;
+
+namespace web {
+class WebState;
+};
+
+namespace reading_list {
+
+// Loads the URL of the |entry| into the |web_state|. If the entry is
+// successfully loaded, marks the entry as read.
+void LoadReadingListEntry(ReadingListEntry const& entry,
+                          ReadingListModel* model,
+                          web::WebState* web_state);
+
+// Loads the distilled URL of the |entry| into the |web_state|, and marks
+// |entry| as read. |entry->DistilledState()| must be |PROCESSED|.
+void LoadReadingListDistilled(ReadingListEntry const& entry,
+                              ReadingListModel* model,
+                              web::WebState* web_state);
+};
+
+#endif  // IOS_CHROME_BROWSER_READING_LIST_READING_LIST_ENTRY_LOADING_UTIL_H_
diff --git a/ios/chrome/browser/reading_list/reading_list_entry_loading_util.mm b/ios/chrome/browser/reading_list/reading_list_entry_loading_util.mm
new file mode 100644
index 0000000..741c4141
--- /dev/null
+++ b/ios/chrome/browser/reading_list/reading_list_entry_loading_util.mm
@@ -0,0 +1,52 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ios/chrome/browser/reading_list/reading_list_entry_loading_util.h"
+
+#include "components/reading_list/ios/reading_list_entry.h"
+#include "components/reading_list/ios/reading_list_model.h"
+#include "ios/chrome/browser/reading_list/offline_url_utils.h"
+#include "ios/chrome/browser/reading_list/reading_list_web_state_observer.h"
+#import "ios/web/public/navigation_manager.h"
+#import "ios/web/public/web_state/web_state.h"
+#include "net/base/network_change_notifier.h"
+
+namespace reading_list {
+
+void LoadReadingListEntry(ReadingListEntry const& entry,
+                          ReadingListModel* model,
+                          web::WebState* web_state) {
+  // TODO(crbug.com/625617): Evaluate whether NetworkChangeNotifier
+  // correctly detects when users are offline.
+  bool open_distilled_entry =
+      net::NetworkChangeNotifier::IsOffline() &&
+      entry.DistilledState() == ReadingListEntry::PROCESSED;
+  if (open_distilled_entry) {
+    return LoadReadingListDistilled(entry, model, web_state);
+  }
+
+  DCHECK(entry.URL().is_valid());
+  web::NavigationManager::WebLoadParams params(entry.URL());
+  params.transition_type = ui::PageTransition::PAGE_TRANSITION_AUTO_BOOKMARK;
+  web_state->GetNavigationManager()->LoadURLWithParams(params);
+  ReadingListWebStateObserver* web_state_observer =
+      ReadingListWebStateObserver::FromWebState(web_state, model);
+  web_state_observer->StartCheckingProgress();
+  model->SetReadStatus(entry.URL(), true);
+}
+
+void LoadReadingListDistilled(ReadingListEntry const& entry,
+                              ReadingListModel* model,
+                              web::WebState* web_state) {
+  DCHECK(entry.DistilledState() == ReadingListEntry::PROCESSED);
+  GURL url =
+      reading_list::DistilledURLForPath(entry.DistilledPath(), entry.URL());
+  DCHECK(url.is_valid());
+  web::NavigationManager::WebLoadParams params(url);
+  params.transition_type = ui::PageTransition::PAGE_TRANSITION_AUTO_BOOKMARK;
+  web_state->GetNavigationManager()->LoadURLWithParams(params);
+  model->SetReadStatus(entry.URL(), true);
+}
+
+}  //  namespace reading_list
diff --git a/ios/chrome/browser/reading_list/reading_list_entry_loading_util_unittest.mm b/ios/chrome/browser/reading_list/reading_list_entry_loading_util_unittest.mm
new file mode 100644
index 0000000..754413088
--- /dev/null
+++ b/ios/chrome/browser/reading_list/reading_list_entry_loading_util_unittest.mm
@@ -0,0 +1,138 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ios/chrome/browser/reading_list/reading_list_entry_loading_util.h"
+
+#include "base/memory/ptr_util.h"
+#include "components/reading_list/ios/reading_list_model_impl.h"
+#include "ios/chrome/browser/reading_list/offline_url_utils.h"
+#import "ios/web/public/navigation_item.h"
+#import "ios/web/public/navigation_manager.h"
+#include "ios/web/public/test/web_test_with_web_state.h"
+#import "ios/web/public/web_state/web_state.h"
+#include "net/base/network_change_notifier.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+// A mock NetworkChangeNotifier that will report the network state passed in the
+// constructor.
+class MockNetworkChangeNotifier : public net::NetworkChangeNotifier {
+ public:
+  MockNetworkChangeNotifier(ConnectionType connection)
+      : NetworkChangeNotifier() {
+    connection_ = connection;
+  }
+
+  ~MockNetworkChangeNotifier() override {}
+
+  ConnectionType GetCurrentConnectionType() const override {
+    return connection_;
+  };
+
+ private:
+  ConnectionType connection_;
+};
+
+// Test fixture to test loading of Reading list entries.
+typedef web::WebTestWithWebState ReadingListEntryLoadingUtilTest;
+
+// Tests that loading a not distilled entry with network will load online
+// version.
+TEST_F(ReadingListEntryLoadingUtilTest, TestLoadEntryOnlineWODistilled) {
+  MockNetworkChangeNotifier network_enabler(
+      net::NetworkChangeNotifier::CONNECTION_WIFI);
+  GURL url("http://foo.bar");
+  auto reading_list_model =
+      base::MakeUnique<ReadingListModelImpl>(nullptr, nullptr);
+  reading_list_model->AddEntry(url, "title");
+  const ReadingListEntry* entry = reading_list_model->GetEntryByURL(url);
+  reading_list::LoadReadingListEntry(*entry, reading_list_model.get(),
+                                     web_state());
+  web::NavigationManager* navigation_manager =
+      web_state()->GetNavigationManager();
+  EXPECT_EQ(navigation_manager->GetPendingItem()->GetURL(), url);
+  EXPECT_TRUE(entry->IsRead());
+}
+
+// Tests that loading a distilled entry with network will load online version.
+TEST_F(ReadingListEntryLoadingUtilTest, TestLoadEntryOnlineWithistilled) {
+  MockNetworkChangeNotifier network_enabler(
+      net::NetworkChangeNotifier::CONNECTION_WIFI);
+  GURL url("http://foo.bar");
+  std::string distilled_path = "distilled/page.html";
+  auto reading_list_model =
+      base::MakeUnique<ReadingListModelImpl>(nullptr, nullptr);
+  reading_list_model->AddEntry(url, "title");
+  reading_list_model->SetEntryDistilledPath(url,
+                                            base::FilePath(distilled_path));
+  const ReadingListEntry* entry = reading_list_model->GetEntryByURL(url);
+  reading_list::LoadReadingListEntry(*entry, reading_list_model.get(),
+                                     web_state());
+  web::NavigationManager* navigation_manager =
+      web_state()->GetNavigationManager();
+  EXPECT_EQ(navigation_manager->GetPendingItem()->GetURL(), url);
+  EXPECT_TRUE(entry->IsRead());
+}
+
+// Tests that loading a not distilled entry without network will load online
+// version.
+TEST_F(ReadingListEntryLoadingUtilTest, TestLoadEntryOfflineWODistilled) {
+  MockNetworkChangeNotifier network_disabler(
+      net::NetworkChangeNotifier::CONNECTION_NONE);
+  GURL url("http://foo.bar");
+  auto reading_list_model =
+      base::MakeUnique<ReadingListModelImpl>(nullptr, nullptr);
+  reading_list_model->AddEntry(url, "title");
+  const ReadingListEntry* entry = reading_list_model->GetEntryByURL(url);
+  reading_list::LoadReadingListEntry(*entry, reading_list_model.get(),
+                                     web_state());
+  web::NavigationManager* navigation_manager =
+      web_state()->GetNavigationManager();
+  EXPECT_EQ(navigation_manager->GetPendingItem()->GetURL(), url);
+  EXPECT_TRUE(entry->IsRead());
+}
+
+// Tests that loading a distilled entry without network will load offline
+// version.
+TEST_F(ReadingListEntryLoadingUtilTest, TestLoadEntryOfflineWithDistilled) {
+  MockNetworkChangeNotifier network_disabler(
+      net::NetworkChangeNotifier::CONNECTION_NONE);
+  GURL url("http://foo.bar");
+  std::string distilled_path = "distilled/page.html";
+  auto reading_list_model =
+      base::MakeUnique<ReadingListModelImpl>(nullptr, nullptr);
+  reading_list_model->AddEntry(url, "title");
+  reading_list_model->SetEntryDistilledPath(url,
+                                            base::FilePath(distilled_path));
+  const ReadingListEntry* entry = reading_list_model->GetEntryByURL(url);
+  reading_list::LoadReadingListEntry(*entry, reading_list_model.get(),
+                                     web_state());
+  web::NavigationManager* navigation_manager =
+      web_state()->GetNavigationManager();
+  EXPECT_NE(navigation_manager->GetPendingItem()->GetURL(), url);
+  EXPECT_EQ(
+      navigation_manager->GetPendingItem()->GetURL(),
+      reading_list::DistilledURLForPath(entry->DistilledPath(), entry->URL()));
+  EXPECT_TRUE(entry->IsRead());
+}
+
+// Tests that loading a distilled version of an entry.
+TEST_F(ReadingListEntryLoadingUtilTest, TestLoadReadingListDistilled) {
+  GURL url("http://foo.bar");
+  std::string distilled_path = "distilled/page.html";
+  auto reading_list_model =
+      base::MakeUnique<ReadingListModelImpl>(nullptr, nullptr);
+  reading_list_model->AddEntry(url, "title");
+  reading_list_model->SetEntryDistilledPath(url,
+                                            base::FilePath(distilled_path));
+  const ReadingListEntry* entry = reading_list_model->GetEntryByURL(url);
+  reading_list::LoadReadingListDistilled(*entry, reading_list_model.get(),
+                                         web_state());
+  web::NavigationManager* navigation_manager =
+      web_state()->GetNavigationManager();
+  EXPECT_NE(navigation_manager->GetPendingItem()->GetURL(), url);
+  EXPECT_EQ(
+      navigation_manager->GetPendingItem()->GetURL(),
+      reading_list::DistilledURLForPath(entry->DistilledPath(), entry->URL()));
+  EXPECT_TRUE(entry->IsRead());
+}
diff --git a/ios/chrome/browser/reading_list/reading_list_web_state_observer.mm b/ios/chrome/browser/reading_list/reading_list_web_state_observer.mm
index d7aab6f..c97630ad 100644
--- a/ios/chrome/browser/reading_list/reading_list_web_state_observer.mm
+++ b/ios/chrome/browser/reading_list/reading_list_web_state_observer.mm
@@ -9,7 +9,7 @@
 #include "base/memory/ptr_util.h"
 #include "components/reading_list/ios/reading_list_model.h"
 #include "ios/chrome/browser/browser_state/chrome_browser_state.h"
-#include "ios/chrome/browser/reading_list/offline_url_utils.h"
+#include "ios/chrome/browser/reading_list/reading_list_entry_loading_util.h"
 #include "ios/chrome/browser/reading_list/reading_list_model_factory.h"
 #include "ios/web/public/navigation_item.h"
 #include "ios/web/public/navigation_manager.h"
@@ -118,11 +118,7 @@
     const ReadingListEntry* entry = reading_list_model_->GetEntryByURL(url);
     if (!entry)
       return;
-    // TODO(crbug.com/664124) Actually load offline pages.
-    GURL distilled_url =
-        reading_list::DistilledURLForPath(entry->DistilledPath());
-    web::NavigationManager::WebLoadParams params(distilled_url);
-    params.transition_type = ui::PAGE_TRANSITION_AUTO_BOOKMARK;
-    navigation_manager->LoadURLWithParams(params);
+    reading_list::LoadReadingListDistilled(*entry, reading_list_model_,
+                                           web_state());
   }
 }
diff --git a/ios/web/BUILD.gn b/ios/web/BUILD.gn
index 6a6ba6fe..f2abbbc 100644
--- a/ios/web/BUILD.gn
+++ b/ios/web/BUILD.gn
@@ -409,6 +409,10 @@
     "public/test/scoped_testing_web_client.mm",
     "public/test/test_browser_state.cc",
     "public/test/test_browser_state.h",
+    "public/test/test_native_content.h",
+    "public/test/test_native_content.mm",
+    "public/test/test_native_content_provider.h",
+    "public/test/test_native_content_provider.mm",
     "public/test/test_redirect_observer.h",
     "public/test/test_redirect_observer.mm",
     "public/test/test_web_client.h",
diff --git a/ios/web/public/test/test_native_content.h b/ios/web/public/test/test_native_content.h
new file mode 100644
index 0000000..cd487dfa
--- /dev/null
+++ b/ios/web/public/test/test_native_content.h
@@ -0,0 +1,22 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IOS_WEB_PUBLIC_TEST_TEST_NATIVE_CONTENT_H_
+#define IOS_WEB_PUBLIC_TEST_TEST_NATIVE_CONTENT_H_
+
+#import "ios/web/public/web_state/ui/crw_native_content.h"
+
+// A test class that implement CRWNativeContent.
+@interface TestNativeContent : NSObject<CRWNativeContent>
+// Inits the CRWNativeContent.
+// |URL| will be returned by the |url| method of the object.
+// If |virtualURL| is valid, it will be returned by the |virtualURL| method.
+// If not, the object will pretend it does not implement |virtualURL|.
+- (instancetype)initWithURL:(const GURL&)URL
+                 virtualURL:(const GURL&)virtualURL NS_DESIGNATED_INITIALIZER;
+
+- (instancetype)init NS_UNAVAILABLE;
+@end
+
+#endif  // IOS_WEB_PUBLIC_TEST_TEST_NATIVE_CONTENT_H_
diff --git a/ios/web/public/test/test_native_content.mm b/ios/web/public/test/test_native_content.mm
new file mode 100644
index 0000000..3b1c5ea4
--- /dev/null
+++ b/ios/web/public/test/test_native_content.mm
@@ -0,0 +1,56 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ios/web/public/test/test_native_content.h"
+
+#include "base/mac/scoped_nsobject.h"
+
+@implementation TestNativeContent {
+  GURL _URL;
+  GURL _virtualURL;
+  base::scoped_nsobject<UIView> _view;
+}
+- (instancetype)initWithURL:(const GURL&)URL
+                 virtualURL:(const GURL&)virtualURL {
+  self = [super init];
+  if (self) {
+    _URL = URL;
+    _virtualURL = virtualURL;
+  }
+  return self;
+}
+
+- (BOOL)respondsToSelector:(SEL)selector {
+  if (selector == @selector(virtualURL)) {
+    return _virtualURL.is_valid();
+  }
+  return [super respondsToSelector:selector];
+}
+
+- (NSString*)title {
+  return @"Test Title";
+}
+
+- (const GURL&)url {
+  return _URL;
+}
+
+- (GURL)virtualURL {
+  return _virtualURL;
+}
+
+- (UIView*)view {
+  return nil;
+}
+
+- (void)handleLowMemory {
+}
+
+- (BOOL)isViewAlive {
+  return YES;
+}
+
+- (void)reload {
+}
+@end
diff --git a/ios/web/public/test/test_native_content_provider.h b/ios/web/public/test/test_native_content_provider.h
new file mode 100644
index 0000000..135a252b
--- /dev/null
+++ b/ios/web/public/test/test_native_content_provider.h
@@ -0,0 +1,20 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IOS_WEB_PUBLIC_TEST_TEST_NATIVE_CONTENT_PROVIDER_H_
+#define IOS_WEB_PUBLIC_TEST_TEST_NATIVE_CONTENT_PROVIDER_H_
+
+#import "ios/web/public/web_state/ui/crw_native_content_provider.h"
+
+@protocol CRWNativeContent;
+
+// A test class that will return CRWNativeContent for specified URLs.
+@interface TestNativeContentProvider : NSObject<CRWNativeContentProvider>
+
+// Add a |CRWNativeContent| for |URL|.
+- (void)setController:(id<CRWNativeContent>)controller forURL:(const GURL&)URL;
+
+@end
+
+#endif  // IOS_WEB_PUBLIC_TEST_TEST_NATIVE_CONTENT_PROVIDER_H_
diff --git a/ios/web/public/test/test_native_content_provider.mm b/ios/web/public/test/test_native_content_provider.mm
new file mode 100644
index 0000000..0033b8e
--- /dev/null
+++ b/ios/web/public/test/test_native_content_provider.mm
@@ -0,0 +1,38 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ios/web/public/test/test_native_content_provider.h"
+
+#include <map>
+
+#include "url/gurl.h"
+
+@implementation TestNativeContentProvider {
+  std::map<GURL, id<CRWNativeContent>> _nativeContent;
+}
+
+- (void)setController:(id<CRWNativeContent>)controller forURL:(const GURL&)URL {
+  _nativeContent[URL] = controller;
+}
+
+- (BOOL)hasControllerForURL:(const GURL&)URL {
+  return _nativeContent.find(URL) != _nativeContent.end();
+}
+
+- (id<CRWNativeContent>)controllerForURL:(const GURL&)URL {
+  auto nativeContent = _nativeContent.find(URL);
+  if (nativeContent == _nativeContent.end()) {
+    return nil;
+  }
+  return nativeContent->second;
+}
+
+- (id<CRWNativeContent>)controllerForURL:(const GURL&)URL
+                               withError:(NSError*)error
+                                  isPost:(BOOL)isPost {
+  NOTREACHED();
+  return nil;
+}
+
+@end
diff --git a/ios/web/public/web_state/ui/crw_native_content.h b/ios/web/public/web_state/ui/crw_native_content.h
index 753656d..994ba6d 100644
--- a/ios/web/public/web_state/ui/crw_native_content.h
+++ b/ios/web/public/web_state/ui/crw_native_content.h
@@ -85,6 +85,10 @@
 // Called when a snapshot of the content will be taken.
 - (void)willUpdateSnapshot;
 
+// The URL that will be displayed to the user when presenting this native
+// content.
+- (GURL)virtualURL;
+
 @end
 
 // CRWNativeContent delegate protocol.
diff --git a/ios/web/web_state/ui/crw_web_controller.mm b/ios/web/web_state/ui/crw_web_controller.mm
index 0d450d8..48d769aa 100644
--- a/ios/web/web_state/ui/crw_web_controller.mm
+++ b/ios/web/web_state/ui/crw_web_controller.mm
@@ -1424,8 +1424,13 @@
   }
   // Any non-web URL source is trusted.
   *trustLevel = web::URLVerificationTrustLevel::kAbsolute;
-  if (self.nativeController)
-    return [self.nativeController url];
+  if (self.nativeController) {
+    if ([self.nativeController respondsToSelector:@selector(virtualURL)]) {
+      return [self.nativeController virtualURL];
+    } else {
+      return [self.nativeController url];
+    }
+  }
   return [self currentNavigationURL];
 }
 
@@ -1997,9 +2002,14 @@
 
   const GURL targetURL = [self currentNavigationURL];
   const web::Referrer referrer;
+  id<CRWNativeContent> nativeContent =
+      [_nativeProvider controllerForURL:targetURL];
   // Unlike the WebView case, always create a new controller and view.
   // TODO(pinkerton): What to do if this does return nil?
-  [self setNativeController:[_nativeProvider controllerForURL:targetURL]];
+  [self setNativeController:nativeContent];
+  if ([nativeContent respondsToSelector:@selector(virtualURL)]) {
+    [self currentNavItem]->SetVirtualURL([nativeContent virtualURL]);
+  }
   [self registerLoadRequest:targetURL
                    referrer:referrer
                  transition:[self currentTransition]];
diff --git a/ios/web/web_state/ui/crw_web_controller_unittest.mm b/ios/web/web_state/ui/crw_web_controller_unittest.mm
index 5ed3e78..f7017315 100644
--- a/ios/web/web_state/ui/crw_web_controller_unittest.mm
+++ b/ios/web/web_state/ui/crw_web_controller_unittest.mm
@@ -19,10 +19,14 @@
 #include "ios/web/navigation/navigation_item_impl.h"
 #import "ios/web/navigation/navigation_manager_impl.h"
 #include "ios/web/public/referrer.h"
+#import "ios/web/public/test/test_native_content.h"
+#import "ios/web/public/test/test_native_content_provider.h"
 #import "ios/web/public/test/test_web_client.h"
 #include "ios/web/public/test/test_web_view_content_view.h"
 #import "ios/web/public/web_state/crw_web_controller_observer.h"
 #import "ios/web/public/web_state/ui/crw_content_view.h"
+#import "ios/web/public/web_state/ui/crw_native_content.h"
+#import "ios/web/public/web_state/ui/crw_native_content_provider.h"
 #import "ios/web/public/web_state/ui/crw_web_view_content_view.h"
 #include "ios/web/public/web_state/url_verification_constants.h"
 #import "ios/web/test/web_test_with_web_controller.h"
@@ -227,7 +231,8 @@
 
 namespace {
 
-NSString* kTestURLString = @"http://www.google.com/";
+const char kTestURLString[] = "http://www.google.com/";
+const char kTestAppSpecificURL[] = "testwebui://test/";
 
 // Returns true if the current device is a large iPhone (6 or 6+).
 bool IsIPhone6Or6Plus() {
@@ -324,7 +329,7 @@
     }
 
     [[result stub] backForwardList];
-    [[[result stub] andReturn:[NSURL URLWithString:kTestURLString]] URL];
+    [[[result stub] andReturn:[NSURL URLWithString:@(kTestURLString)]] URL];
     [[result stub] setNavigationDelegate:OCMOCK_ANY];
     [[result stub] setUIDelegate:OCMOCK_ANY];
     [[result stub] setFrame:ExpectedWebViewFrame()];
@@ -795,7 +800,7 @@
 }
 
 TEST_F(CRWWebControllerTest, WebUrlWithTrustLevel) {
-  [[[mockWebView_ stub] andReturn:[NSURL URLWithString:kTestURLString]] URL];
+  [[[mockWebView_ stub] andReturn:[NSURL URLWithString:@(kTestURLString)]] URL];
   [[[mockWebView_ stub] andReturnBool:NO] hasOnlySecureContent];
 
   // Stub out the injection process.
@@ -803,8 +808,7 @@
                         completionHandler:OCMOCK_ANY];
 
   // Simulate registering load request to avoid failing page load simulation.
-  [web_controller()
-      simulateLoadRequestWithURL:GURL([kTestURLString UTF8String])];
+  [web_controller() simulateLoadRequestWithURL:GURL(kTestURLString)];
   // Simulate a page load to trigger a URL update.
   [static_cast<id<WKNavigationDelegate>>(web_controller()) webView:mockWebView_
                                                didCommitNavigation:nil];
@@ -812,10 +816,79 @@
   web::URLVerificationTrustLevel trust_level = web::kNone;
   GURL gurl = [web_controller() currentURLWithTrustLevel:&trust_level];
 
-  EXPECT_EQ(gurl, GURL(base::SysNSStringToUTF8(kTestURLString)));
+  EXPECT_EQ(gurl, GURL(kTestURLString));
   EXPECT_EQ(web::kAbsolute, trust_level);
 }
 
+// Test fixture for testing CRWWebController presenting native content.
+class CRWWebControllerNativeContentTest : public web::WebTestWithWebController {
+ protected:
+  void SetUp() override {
+    web::WebTestWithWebController::SetUp();
+    mock_native_provider_.reset([[TestNativeContentProvider alloc] init]);
+    [web_controller() setNativeProvider:mock_native_provider_];
+  }
+
+  void Load(const GURL& URL) {
+    NavigationManagerImpl& navigation_manager =
+        [web_controller() webStateImpl]->GetNavigationManagerImpl();
+    navigation_manager.InitializeSession(@"name", nil, NO, 0);
+    [navigation_manager.GetSessionController()
+          addPendingEntry:URL
+                 referrer:web::Referrer()
+               transition:ui::PAGE_TRANSITION_TYPED
+        rendererInitiated:NO];
+    [web_controller() loadCurrentURL];
+  }
+
+  base::scoped_nsobject<TestNativeContentProvider> mock_native_provider_;
+};
+
+// Tests WebState and NavigationManager correctly return native content URL.
+TEST_F(CRWWebControllerNativeContentTest, NativeContentURL) {
+  GURL url_to_load(kTestAppSpecificURL);
+  base::scoped_nsobject<TestNativeContent> content(
+      [[TestNativeContent alloc] initWithURL:url_to_load virtualURL:GURL()]);
+  [mock_native_provider_ setController:content forURL:url_to_load];
+  Load(url_to_load);
+  web::URLVerificationTrustLevel trust_level = web::kNone;
+  GURL gurl = [web_controller() currentURLWithTrustLevel:&trust_level];
+  EXPECT_EQ(gurl, url_to_load);
+  EXPECT_EQ(web::kAbsolute, trust_level);
+  EXPECT_EQ([web_controller() webState]->GetVisibleURL(), url_to_load);
+  NavigationManagerImpl& navigationManager =
+      [web_controller() webStateImpl]->GetNavigationManagerImpl();
+  EXPECT_EQ(navigationManager.GetVisibleItem()->GetURL(), url_to_load);
+  EXPECT_EQ(navigationManager.GetVisibleItem()->GetVirtualURL(), url_to_load);
+  EXPECT_EQ(navigationManager.GetLastCommittedItem()->GetURL(), url_to_load);
+  EXPECT_EQ(navigationManager.GetLastCommittedItem()->GetVirtualURL(),
+            url_to_load);
+}
+
+// Tests WebState and NavigationManager correctly return native content URL and
+// VirtualURL
+TEST_F(CRWWebControllerNativeContentTest, NativeContentVirtualURL) {
+  GURL url_to_load(kTestAppSpecificURL);
+  GURL virtual_url(kTestURLString);
+  base::scoped_nsobject<TestNativeContent> content([[TestNativeContent alloc]
+      initWithURL:virtual_url
+       virtualURL:virtual_url]);
+  [mock_native_provider_ setController:content forURL:url_to_load];
+  Load(url_to_load);
+  web::URLVerificationTrustLevel trust_level = web::kNone;
+  GURL gurl = [web_controller() currentURLWithTrustLevel:&trust_level];
+  EXPECT_EQ(gurl, virtual_url);
+  EXPECT_EQ(web::kAbsolute, trust_level);
+  EXPECT_EQ([web_controller() webState]->GetVisibleURL(), virtual_url);
+  NavigationManagerImpl& navigationManager =
+      [web_controller() webStateImpl]->GetNavigationManagerImpl();
+  EXPECT_EQ(navigationManager.GetVisibleItem()->GetURL(), url_to_load);
+  EXPECT_EQ(navigationManager.GetVisibleItem()->GetVirtualURL(), virtual_url);
+  EXPECT_EQ(navigationManager.GetLastCommittedItem()->GetURL(), url_to_load);
+  EXPECT_EQ(navigationManager.GetLastCommittedItem()->GetVirtualURL(),
+            virtual_url);
+}
+
 // A separate test class, as none of the |CRWUIWebViewWebControllerTest| setup
 // is needed;
 typedef web::WebTestWithWebController CRWWebControllerObserversTest;
diff --git a/media/audio/alsa/audio_manager_alsa.cc b/media/audio/alsa/audio_manager_alsa.cc
index 3886d668..72c48e3 100644
--- a/media/audio/alsa/audio_manager_alsa.cc
+++ b/media/audio/alsa/audio_manager_alsa.cc
@@ -127,6 +127,10 @@
       kDefaultSampleRate, 16, kDefaultInputBufferSize);
 }
 
+const char* AudioManagerAlsa::GetName() {
+  return "ALSA";
+}
+
 void AudioManagerAlsa::GetAlsaAudioDevices(StreamType type,
                                            AudioDeviceNames* device_names) {
   // Constants specified by the ALSA API for device hints.
diff --git a/media/audio/alsa/audio_manager_alsa.h b/media/audio/alsa/audio_manager_alsa.h
index a4c6242..8dff467 100644
--- a/media/audio/alsa/audio_manager_alsa.h
+++ b/media/audio/alsa/audio_manager_alsa.h
@@ -35,6 +35,7 @@
   void GetAudioOutputDeviceNames(AudioDeviceNames* device_names) override;
   AudioParameters GetInputStreamParameters(
       const std::string& device_id) override;
+  const char* GetName() override;
 
   // Implementation of AudioManagerBase.
   AudioOutputStream* MakeLinearOutputStream(
diff --git a/media/audio/android/audio_manager_android.cc b/media/audio/android/audio_manager_android.cc
index 9f18d5d..502a8cbf 100644
--- a/media/audio/android/audio_manager_android.cc
+++ b/media/audio/android/audio_manager_android.cc
@@ -161,6 +161,10 @@
   return params;
 }
 
+const char* AudioManagerAndroid::GetName() {
+  return "Android";
+}
+
 AudioOutputStream* AudioManagerAndroid::MakeAudioOutputStream(
     const AudioParameters& params,
     const std::string& device_id,
diff --git a/media/audio/android/audio_manager_android.h b/media/audio/android/audio_manager_android.h
index ec38dcc6..2f3f250 100644
--- a/media/audio/android/audio_manager_android.h
+++ b/media/audio/android/audio_manager_android.h
@@ -45,6 +45,7 @@
       const LogCallback& log_callback) override;
   void ReleaseOutputStream(AudioOutputStream* stream) override;
   void ReleaseInputStream(AudioInputStream* stream) override;
+  const char* GetName() override;
 
   // Implementation of AudioManagerBase.
   AudioOutputStream* MakeLinearOutputStream(
diff --git a/media/audio/audio_manager.h b/media/audio/audio_manager.h
index 666fa1b..887521a 100644
--- a/media/audio/audio_manager.h
+++ b/media/audio/audio_manager.h
@@ -253,6 +253,9 @@
   virtual std::unique_ptr<AudioLog> CreateAudioLog(
       AudioLogFactory::AudioComponent component) = 0;
 
+  // Gets the name of the audio manager (e.g., Windows, Mac, PulseAudio).
+  virtual const char* GetName() = 0;
+
  protected:
   AudioManager(scoped_refptr<base::SingleThreadTaskRunner> task_runner,
                scoped_refptr<base::SingleThreadTaskRunner> worker_task_runner);
diff --git a/media/audio/audio_output_proxy_unittest.cc b/media/audio/audio_output_proxy_unittest.cc
index a8754ee..37e012a 100644
--- a/media/audio/audio_output_proxy_unittest.cc
+++ b/media/audio/audio_output_proxy_unittest.cc
@@ -116,6 +116,7 @@
                scoped_refptr<base::SingleThreadTaskRunner>());
   MOCK_METHOD1(GetAudioInputDeviceNames, void(
       media::AudioDeviceNames* device_name));
+  MOCK_METHOD0(GetName, const char*());
 
   MOCK_METHOD2(MakeLinearOutputStream,
                AudioOutputStream*(const AudioParameters& params,
diff --git a/media/audio/cras/audio_manager_cras.cc b/media/audio/cras/audio_manager_cras.cc
index 6df14bc87..c4bef24 100644
--- a/media/audio/cras/audio_manager_cras.cc
+++ b/media/audio/cras/audio_manager_cras.cc
@@ -228,6 +228,10 @@
   return params;
 }
 
+const char* AudioManagerCras::GetName() {
+  return "CRAS";
+}
+
 AudioOutputStream* AudioManagerCras::MakeLinearOutputStream(
     const AudioParameters& params,
     const LogCallback& log_callback) {
diff --git a/media/audio/cras/audio_manager_cras.h b/media/audio/cras/audio_manager_cras.h
index ec739468..ddf0aac 100644
--- a/media/audio/cras/audio_manager_cras.h
+++ b/media/audio/cras/audio_manager_cras.h
@@ -31,6 +31,7 @@
   void GetAudioOutputDeviceNames(AudioDeviceNames* device_names) override;
   AudioParameters GetInputStreamParameters(
       const std::string& device_id) override;
+  const char* GetName() override;
 
   // AudioManagerBase implementation.
   AudioOutputStream* MakeLinearOutputStream(
diff --git a/media/audio/fake_audio_manager.cc b/media/audio/fake_audio_manager.cc
index 2915e72..07e88a5 100644
--- a/media/audio/fake_audio_manager.cc
+++ b/media/audio/fake_audio_manager.cc
@@ -34,6 +34,10 @@
 
 bool FakeAudioManager::HasAudioInputDevices() { return false; }
 
+const char* FakeAudioManager::GetName() {
+  return "Fake";
+}
+
 // Implementation of AudioManagerBase.
 AudioOutputStream* FakeAudioManager::MakeLinearOutputStream(
     const AudioParameters& params,
diff --git a/media/audio/fake_audio_manager.h b/media/audio/fake_audio_manager.h
index 94276b2..022c664 100644
--- a/media/audio/fake_audio_manager.h
+++ b/media/audio/fake_audio_manager.h
@@ -24,6 +24,7 @@
   // Implementation of AudioManager.
   bool HasAudioOutputDevices() override;
   bool HasAudioInputDevices() override;
+  const char* GetName() override;
 
   // Implementation of AudioManagerBase.
   AudioOutputStream* MakeLinearOutputStream(
diff --git a/media/audio/mac/audio_manager_mac.cc b/media/audio/mac/audio_manager_mac.cc
index 14877a95..37c9658 100644
--- a/media/audio/mac/audio_manager_mac.cc
+++ b/media/audio/mac/audio_manager_mac.cc
@@ -603,6 +603,10 @@
   return std::string();
 }
 
+const char* AudioManagerMac::GetName() {
+  return "Mac";
+}
+
 AudioOutputStream* AudioManagerMac::MakeLinearOutputStream(
     const AudioParameters& params,
     const LogCallback& log_callback) {
diff --git a/media/audio/mac/audio_manager_mac.h b/media/audio/mac/audio_manager_mac.h
index 40d98eb..84fdd800 100644
--- a/media/audio/mac/audio_manager_mac.h
+++ b/media/audio/mac/audio_manager_mac.h
@@ -43,6 +43,7 @@
       const std::string& device_id) override;
   std::string GetAssociatedOutputDeviceID(
       const std::string& input_device_id) override;
+  const char* GetName() override;
 
   // Implementation of AudioManagerBase.
   AudioOutputStream* MakeLinearOutputStream(
diff --git a/media/audio/mock_audio_manager.cc b/media/audio/mock_audio_manager.cc
index 5676b311..2fbc2859 100644
--- a/media/audio/mock_audio_manager.cc
+++ b/media/audio/mock_audio_manager.cc
@@ -105,4 +105,8 @@
   return nullptr;
 }
 
+const char* MockAudioManager::GetName() {
+  return nullptr;
+}
+
 }  // namespace media.
diff --git a/media/audio/mock_audio_manager.h b/media/audio/mock_audio_manager.h
index e77e85c..735adf6 100644
--- a/media/audio/mock_audio_manager.h
+++ b/media/audio/mock_audio_manager.h
@@ -62,6 +62,8 @@
   std::unique_ptr<AudioLog> CreateAudioLog(
       AudioLogFactory::AudioComponent component) override;
 
+  const char* GetName() override;
+
  protected:
   ~MockAudioManager() override;
 
diff --git a/media/audio/pulse/audio_manager_pulse.cc b/media/audio/pulse/audio_manager_pulse.cc
index afa7064..779bf92e 100644
--- a/media/audio/pulse/audio_manager_pulse.cc
+++ b/media/audio/pulse/audio_manager_pulse.cc
@@ -143,6 +143,10 @@
                          buffer_size);
 }
 
+const char* AudioManagerPulse::GetName() {
+  return "PulseAudio";
+}
+
 AudioOutputStream* AudioManagerPulse::MakeLinearOutputStream(
     const AudioParameters& params,
     const LogCallback& log_callback) {
diff --git a/media/audio/pulse/audio_manager_pulse.h b/media/audio/pulse/audio_manager_pulse.h
index bd66091..662c461 100644
--- a/media/audio/pulse/audio_manager_pulse.h
+++ b/media/audio/pulse/audio_manager_pulse.h
@@ -32,6 +32,7 @@
   void GetAudioOutputDeviceNames(AudioDeviceNames* device_names) override;
   AudioParameters GetInputStreamParameters(
       const std::string& device_id) override;
+  const char* GetName() override;
 
   // Implementation of AudioManagerBase.
   AudioOutputStream* MakeLinearOutputStream(
diff --git a/media/audio/win/audio_manager_win.cc b/media/audio/win/audio_manager_win.cc
index 89e9eab4..21f15cd 100644
--- a/media/audio/win/audio_manager_win.cc
+++ b/media/audio/win/audio_manager_win.cc
@@ -331,6 +331,10 @@
   return CoreAudioUtil::GetMatchingOutputDeviceID(input_device_id);
 }
 
+const char* AudioManagerWin::GetName() {
+  return "Windows";
+}
+
 // Factory for the implementations of AudioOutputStream for AUDIO_PCM_LINEAR
 // mode.
 // - PCMWaveOutAudioOutputStream: Based on the waveOut API.
diff --git a/media/audio/win/audio_manager_win.h b/media/audio/win/audio_manager_win.h
index a8b6206..5a5395c3 100644
--- a/media/audio/win/audio_manager_win.h
+++ b/media/audio/win/audio_manager_win.h
@@ -36,6 +36,7 @@
       const std::string& device_id) override;
   std::string GetAssociatedOutputDeviceID(
       const std::string& input_device_id) override;
+  const char* GetName() override;
 
   // Implementation of AudioManagerBase.
   AudioOutputStream* MakeLinearOutputStream(
diff --git a/testing/libfuzzer/archive_corpus.py b/testing/libfuzzer/archive_corpus.py
index 7e39bb5..71c132b 100755
--- a/testing/libfuzzer/archive_corpus.py
+++ b/testing/libfuzzer/archive_corpus.py
@@ -13,6 +13,7 @@
 import argparse
 import os
 import sys
+import warnings
 import zipfile
 
 
@@ -31,8 +32,13 @@
       corpus_files.append(full_filename)
 
   with zipfile.ZipFile(args.output, 'w') as z:
-    for corpus_file in corpus_files:
-        z.write(corpus_file, os.path.basename(corpus_file))
+    # Turn warnings into errors to interrupt the build: crbug.com/653920.
+    with warnings.catch_warnings():
+      warnings.simplefilter("error")
+      for i, corpus_file in enumerate(corpus_files):
+        # To avoid duplication of filenames inside the archive, use numbers.
+        arcname = '%016d' % i
+        z.write(corpus_file, arcname)
 
 
 if __name__ == '__main__':
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations
index 2a95d0f..63a69ff 100644
--- a/third_party/WebKit/LayoutTests/TestExpectations
+++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -1927,5 +1927,8 @@
 Bug(dpranke) imported/wpt/workers/Worker_cross_origin_security_err.htm [ Failure ]
 Bug(dpranke) imported/wpt/service-workers/service-worker/register-closed-window.https.html [ Timeout ]
 
+crbug.com/658605 paint/invalidation/flexbox/scrollbars-changed.html [ NeedsRebaseline ]
+crbug.com/658605 paint/invalidation/multicol-repaint.html  [ NeedsRebaseline ]
+
 # Added 2016-11-30
 crbug.com/669911 [ Win7 Win10 ] virtual/threaded/animations/zoom-responsive-transform-animation.html [ Pass Failure Timeout ]
diff --git a/third_party/WebKit/LayoutTests/editing/selection/set_base_and_extent/set_null.html b/third_party/WebKit/LayoutTests/editing/selection/set_base_and_extent/set_null.html
new file mode 100644
index 0000000..cca44b4
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/editing/selection/set_base_and_extent/set_null.html
@@ -0,0 +1,38 @@
+<!doctype html>
+<script src="../../../resources/testharness.js"></script>
+<script src="../../../resources/testharnessreport.js"></script>
+<script src="../../assert_selection.js"></script>
+<div id="log"></div>
+<script>
+test(() => {
+assert_selection(
+  '<div>^foo|</div>',
+  selection => {
+    selection.setBaseAndExtent(null, 0, null, 0);
+  },
+  '<div>foo</div>',
+  'Setting both null clears selection');
+
+assert_selection(
+  '<div>^foo|</div>',
+  selection => {
+    selection.setBaseAndExtent(null, 1, null, 2);
+  },
+  '<div>foo</div>',
+  'Setting both null clears selection');
+
+assert_selection(
+  '<div>^foo|</div>',
+  selection => selection.setBaseAndExtent(null, 1, selection.document.querySelector('div'), 1),
+  '<div>foo</div>',
+  'Setting only base null clears selection');
+
+assert_selection(
+  '<div>foo</div>',
+  selection => selection.setBaseAndExtent(selection.document.querySelector('div'), 0, null, 2),
+  '<div>|foo</div>',
+  'Setting base non-null and extent null behaves as collapse.' +
+  'This is under discussion: https://github.com/w3c/selection-api/issues/72');
+
+}, 'setBaseAndExtent with null.');
+</script>
diff --git a/third_party/WebKit/LayoutTests/fast/css3-text/css3-word-break/word-break-break-all-in-span-expected.html b/third_party/WebKit/LayoutTests/fast/css3-text/css3-word-break/word-break-break-all-in-span-expected.html
new file mode 100644
index 0000000..1621c09
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/css3-text/css3-word-break/word-break-break-all-in-span-expected.html
@@ -0,0 +1,34 @@
+<!DOCTYPE html>
+<style>
+@font-face {
+  font-family:cssot;
+  src:url(../../../third_party/adobe-fonts/CSSFWOrientationTest.otf);
+}
+div {
+  font-family: Ahem, cssot;
+  width: 5em;
+  font-size: 20px;
+  border: 5px blue solid;
+  display: inline-block;
+  margin-bottom: .2em;
+  margin-right: 3em;
+}
+.break-all {
+  color: orange;
+}
+</style>
+<body>
+  <p>Test break-all applied to span works as expected.</p>
+  <div>AAAA<span class="break-all">X<br>XXXXX</span></div>
+  <div>AAAAA<span class="break-all">X<br>XXXXX</span></div>
+  <div>AAAAAA<span class="break-all">X<br>XXXXX</span></div>
+  <div>A AA<span class="break-all">X<br>XXXXX</span></div>
+  <div>AA<br>AA<span class="break-all">XXX</span></div>
+  <div>AAA<br>AA<span class="break-all">XXX</span></div>
+  <div>AAAA<br>AA<span class="break-all">XXX</span></div>
+  <div>AAAAA<br>AA<span class="break-all">XXX</span></div>
+  <div>AAA<br>A<span class="break-all">XXXX</span></div>
+  <div>AAAA<br>A<span class="break-all">XXXX</span></div>
+  <div>AAAAA<br>A<span class="break-all">XXXX</span></div>
+  <div>国国国国<br>国、<span class="break-all">XXX</span></div>
+</body>
diff --git a/third_party/WebKit/LayoutTests/fast/css3-text/css3-word-break/word-break-break-all-in-span.html b/third_party/WebKit/LayoutTests/fast/css3-text/css3-word-break/word-break-break-all-in-span.html
new file mode 100644
index 0000000..9e80231
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/css3-text/css3-word-break/word-break-break-all-in-span.html
@@ -0,0 +1,35 @@
+<!DOCTYPE html>
+<style>
+@font-face {
+  font-family:cssot;
+  src:url(../../../third_party/adobe-fonts/CSSFWOrientationTest.otf);
+}
+div {
+  font-family: Ahem, cssot;
+  width: 5em;
+  font-size: 20px;
+  border: 5px blue solid;
+  display: inline-block;
+  margin-bottom: .2em;
+  margin-right: 3em;
+}
+.break-all {
+  word-break: break-all;
+  color: orange;
+}
+</style>
+<body>
+  <p>Test break-all applied to span works as expected.</p>
+  <div>AAAA<span class="break-all">XXXXXX</span></div>
+  <div>AAAAA<span class="break-all">XXXXXX</span></div>
+  <div>AAAAAA<span class="break-all">XXXXXX</span></div>
+  <div>A AA<span class="break-all">XXXXXX</span></div>
+  <div>AA AA<span class="break-all">XXX</span></div>
+  <div>AAA AA<span class="break-all">XXX</span></div>
+  <div>AAAA AA<span class="break-all">XXX</span></div>
+  <div>AAAAA AA<span class="break-all">XXX</span></div>
+  <div>AAA A<span class="break-all">XXXX</span></div>
+  <div>AAAA A<span class="break-all">XXXX</span></div>
+  <div>AAAAA A<span class="break-all">XXXX</span></div>
+  <div>国国国国国、<span class="break-all">XXX</span></div>
+</body>
diff --git a/third_party/WebKit/LayoutTests/fast/dom/HTMLElement/set-inner-outer-optimization.html b/third_party/WebKit/LayoutTests/fast/dom/HTMLElement/set-inner-outer-optimization.html
index 1a14e28..7016854 100644
--- a/third_party/WebKit/LayoutTests/fast/dom/HTMLElement/set-inner-outer-optimization.html
+++ b/third_party/WebKit/LayoutTests/fast/dom/HTMLElement/set-inner-outer-optimization.html
@@ -74,8 +74,8 @@
     runTest('', 'innerHTML', '<a></a><b></b>', 'modified');
 
     runTest('text', 'innerHTML', '', 'modified');
-    runTest('text', 'innerHTML', 'different text', 'modified, with same first child');
-    runTest('text', 'innerHTML', 'text', 'not modified');
+    runTest('text', 'innerHTML', 'different text', 'modified');
+    runTest('text', 'innerHTML', 'text', 'modified');
     runTest('text', 'innerHTML', '<a></a>', 'modified');
     runTest('text', 'innerHTML', '<a></a><b></b>', 'modified');
 
diff --git a/third_party/WebKit/LayoutTests/fast/dom/adopt-node-crash-expected.txt b/third_party/WebKit/LayoutTests/fast/dom/adopt-node-crash-expected.txt
deleted file mode 100644
index b2bf751..0000000
--- a/third_party/WebKit/LayoutTests/fast/dom/adopt-node-crash-expected.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-Tests for a crash due to modifying the DOM during mutation events due to an adoptNode call. If this page doesn't crash and DOMSubtreeModified is fire, this test succeeds.
-DOMSubtreeModified fired
-
diff --git a/third_party/WebKit/LayoutTests/fast/dom/adopt-node-crash.html b/third_party/WebKit/LayoutTests/fast/dom/adopt-node-crash.html
deleted file mode 100644
index 52b0e62..0000000
--- a/third_party/WebKit/LayoutTests/fast/dom/adopt-node-crash.html
+++ /dev/null
@@ -1,24 +0,0 @@
-<!DOCTYPE html>
-<div>Tests for a crash due to modifying the DOM during mutation events due to an adoptNode call. If this page doesn't crash and DOMSubtreeModified is fire, this test succeeds.</div>
-<div id="result"></div>
-<div id="node-to-adopt"></div>
-<iframe></iframe>
-<script>
-if (window.testRunner)
-    testRunner.dumpAsText();
-
-var nodeToAdopt = document.getElementById('node-to-adopt');
-
-var mutationHandler = function() {
-    document.getElementById('result').innerHTML = "DOMSubtreeModified fired";
-    document.body.removeEventListener('DOMSubtreeModified', mutationHandler, true);
-    document.body.appendChild(nodeToAdopt);
-};
-document.body.addEventListener('DOMSubtreeModified', mutationHandler, true);
-
-var iframe = document.querySelector('iframe');
-var iframeDoc = iframe.contentDocument;
-iframeDoc.adoptNode(nodeToAdopt);
-// The crash happens when the iframe's document is getting detached.
-document.body.removeChild(iframe);
-</script>
diff --git a/third_party/WebKit/LayoutTests/fast/events/crash-on-mutate-during-drop-expected.txt b/third_party/WebKit/LayoutTests/fast/events/crash-on-mutate-during-drop-expected.txt
deleted file mode 100644
index 53cdf1e..0000000
--- a/third_party/WebKit/LayoutTests/fast/events/crash-on-mutate-during-drop-expected.txt
+++ /dev/null
@@ -1 +0,0 @@
-PASSED
diff --git a/third_party/WebKit/LayoutTests/fast/events/crash-on-mutate-during-drop.html b/third_party/WebKit/LayoutTests/fast/events/crash-on-mutate-during-drop.html
deleted file mode 100644
index e5e2b876..0000000
--- a/third_party/WebKit/LayoutTests/fast/events/crash-on-mutate-during-drop.html
+++ /dev/null
@@ -1,41 +0,0 @@
-<html>
-<head>
-<script>
-function foo() {
-    if (event.type == "DOMNodeInserted" && event.target.nodeType == 3)
-        document.body.innerHTML = "PASSED";
-}
-
-function runTest() {
-    if (!window.testRunner)
-      return;
-
-    window.testRunner.dumpAsText();
-
-    document.addEventListener("DOMNodeInserted", function() { foo() }, true);
-
-    // Select the element 'dragSource'.
-    var selection = window.getSelection();
-    var range =  document.createRange();
-    range.selectNode(document.getElementById("dragSource"));
-    selection.addRange(range);
-
-    // Drag the source text to the target text.
-    var source = document.getElementById('dragSource');
-    var target = document.getElementById('dragTarget');
-    eventSender.mouseMoveTo(source.offsetLeft + 2, source.offsetTop + 2);
-    eventSender.mouseDown();
-    eventSender.leapForward(500);
-    eventSender.mouseMoveTo(target.offsetLeft + target.offsetWidth / 2,
-                            target.offsetTop + target.offsetHeight / 2);
-    eventSender.mouseUp();
-}
-</script>
-</head>
-<body contenteditable="true" onload="runTest()">
-<p>This test tests for a crash when a DOM mutation event listener
-   modifies the text during a drop. If the test doesn't crash, all is good.
-<p id="dragSource">drag source text
-<p id="dragTarget">drag dest text
-</body>
-</html>
\ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/fragmentation/first-child-large-top-margin.html b/third_party/WebKit/LayoutTests/fragmentation/first-child-large-top-margin.html
new file mode 100644
index 0000000..391d4c5c
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fragmentation/first-child-large-top-margin.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<p>There should be a blue square below.</p>
+<div style="position:relative; columns:2; column-gap:0; column-fill:auto; width:200px; height:100px;">
+    <div id="elm" style="margin-top:150px; height:100px; background:blue;"></div>
+</div>
+<script src="../resources/testharness.js"></script>
+<script src="../resources/testharnessreport.js"></script>
+<script>
+test(() => {
+    var elm = document.getElementById("elm");
+    assert_equals(elm.offsetLeft, 100);
+    assert_equals(elm.offsetTop, 0);
+}, "Margins should collapse with fragmentainer boundaries");
+</script>
diff --git a/third_party/WebKit/LayoutTests/fragmentation/margin-bottom-at-top-of-fragmentainer.html b/third_party/WebKit/LayoutTests/fragmentation/margin-bottom-at-top-of-fragmentainer.html
new file mode 100644
index 0000000..12fe70a2
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fragmentation/margin-bottom-at-top-of-fragmentainer.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<p>There should be a blue square below.</p>
+<div style="position:relative; columns:2; column-gap:0; column-fill:auto; width:200px; height:100px;">
+    <div style="margin-bottom:50px; height:100px;"></div>
+    <div id="elm" style="height:100px; background:blue;"></div>
+</div>
+<script src="../resources/testharness.js"></script>
+<script src="../resources/testharnessreport.js"></script>
+<script>
+test(() => {
+    var elm = document.getElementById("elm");
+    assert_equals(elm.offsetLeft, 100);
+    assert_equals(elm.offsetTop, 0);
+}, "Margins should collapse with fragmentainer boundaries");
+</script>
diff --git a/third_party/WebKit/LayoutTests/fragmentation/margin-top-at-top-of-fragmentainer.html b/third_party/WebKit/LayoutTests/fragmentation/margin-top-at-top-of-fragmentainer.html
new file mode 100644
index 0000000..6b20f8e9
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fragmentation/margin-top-at-top-of-fragmentainer.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<p>There should be a blue square below.</p>
+<div style="position:relative; columns:2; column-gap:0; column-fill:auto; width:200px; height:100px;">
+    <div style="height:100px;"></div>
+    <div id="elm" style="margin-top:50px; height:100px; background:blue;"></div>
+</div>
+<script src="../resources/testharness.js"></script>
+<script src="../resources/testharnessreport.js"></script>
+<script>
+test(() => {
+    var elm = document.getElementById("elm");
+    assert_equals(elm.offsetLeft, 100);
+    assert_equals(elm.offsetTop, 0);
+}, "Margins should collapse with fragmentainer boundaries");
+</script>
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/1.1/stylehash-basic-blocked-error-event-expected.txt b/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/1.1/stylehash-basic-blocked-error-event-expected.txt
index 389fc1c..008fd471 100644
--- a/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/1.1/stylehash-basic-blocked-error-event-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/1.1/stylehash-basic-blocked-error-event-expected.txt
@@ -4,6 +4,8 @@
 
 CONSOLE ERROR: line 28: Refused to apply inline style because it violates the following Content Security Policy directive: "style-src 'sha1-pfeR5wMA6np45oqDTP6Pj3tLpJo='". Either the 'unsafe-inline' keyword, a hash ('sha256-pckGv9YvNcB5xy+Y4fbqhyo+ib850wyiuWeNbZvLi00='), or a nonce ('nonce-...') is required to enable inline execution.
 
+CONSOLE ERROR: line 37: Refused to apply inline style because it violates the following Content Security Policy directive: "style-src 'sha1-pfeR5wMA6np45oqDTP6Pj3tLpJo='". Either the 'unsafe-inline' keyword, a hash ('sha256-47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU='), or a nonce ('nonce-...') is required to enable inline execution.
+
 CONSOLE ERROR: line 37: Refused to apply inline style because it violates the following Content Security Policy directive: "style-src 'sha1-pfeR5wMA6np45oqDTP6Pj3tLpJo='". Either the 'unsafe-inline' keyword, a hash ('sha256-QSqLgiKqPxCeZH1d3vWR+4HJOthCVhvG1P/AFaVJfR4='), or a nonce ('nonce-...') is required to enable inline execution.
 
 This is a testharness.js-based test.
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/1.1/stylehash-svg-style-basic-blocked-error-event-expected.txt b/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/1.1/stylehash-svg-style-basic-blocked-error-event-expected.txt
index 37e3444..d1217d5 100644
--- a/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/1.1/stylehash-svg-style-basic-blocked-error-event-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/1.1/stylehash-svg-style-basic-blocked-error-event-expected.txt
@@ -2,6 +2,8 @@
 
 CONSOLE ERROR: line 19: Refused to apply inline style because it violates the following Content Security Policy directive: "style-src 'sha1-pfeR5wMA6np45oqDTP6Pj3tLpJo='". Either the 'unsafe-inline' keyword, a hash ('sha256-pckGv9YvNcB5xy+Y4fbqhyo+ib850wyiuWeNbZvLi00='), or a nonce ('nonce-...') is required to enable inline execution.
 
+CONSOLE ERROR: line 28: Refused to apply inline style because it violates the following Content Security Policy directive: "style-src 'sha1-pfeR5wMA6np45oqDTP6Pj3tLpJo='". Either the 'unsafe-inline' keyword, a hash ('sha256-47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU='), or a nonce ('nonce-...') is required to enable inline execution.
+
 CONSOLE ERROR: line 28: Refused to apply inline style because it violates the following Content Security Policy directive: "style-src 'sha1-pfeR5wMA6np45oqDTP6Pj3tLpJo='". Either the 'unsafe-inline' keyword, a hash ('sha256-QSqLgiKqPxCeZH1d3vWR+4HJOthCVhvG1P/AFaVJfR4='), or a nonce ('nonce-...') is required to enable inline execution.
 
 This is a testharness.js-based test.
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/nonces/stylenonce-basic-blocked-error-event-expected.txt b/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/nonces/stylenonce-basic-blocked-error-event-expected.txt
index 1cec67e..b198e81 100644
--- a/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/nonces/stylenonce-basic-blocked-error-event-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/nonces/stylenonce-basic-blocked-error-event-expected.txt
@@ -2,6 +2,8 @@
 
 CONSOLE ERROR: line 19: Refused to apply inline style because it violates the following Content Security Policy directive: "style-src 'nonce-nonceynonce'". Either the 'unsafe-inline' keyword, a hash ('sha256-pckGv9YvNcB5xy+Y4fbqhyo+ib850wyiuWeNbZvLi00='), or a nonce ('nonce-...') is required to enable inline execution.
 
+CONSOLE ERROR: line 28: Refused to apply inline style because it violates the following Content Security Policy directive: "style-src 'nonce-nonceynonce'". Either the 'unsafe-inline' keyword, a hash ('sha256-47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU='), or a nonce ('nonce-...') is required to enable inline execution.
+
 CONSOLE ERROR: line 28: Refused to apply inline style because it violates the following Content Security Policy directive: "style-src 'nonce-nonceynonce'". Either the 'unsafe-inline' keyword, a hash ('sha256-QSqLgiKqPxCeZH1d3vWR+4HJOthCVhvG1P/AFaVJfR4='), or a nonce ('nonce-...') is required to enable inline execution.
 
 This is a testharness.js-based test.
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/nonces/stylenonce-svg-style-basic-blocked-error-event-expected.txt b/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/nonces/stylenonce-svg-style-basic-blocked-error-event-expected.txt
index 7f155c4..6b7d333 100644
--- a/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/nonces/stylenonce-svg-style-basic-blocked-error-event-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/nonces/stylenonce-svg-style-basic-blocked-error-event-expected.txt
@@ -2,6 +2,8 @@
 
 CONSOLE ERROR: line 19: Refused to apply inline style because it violates the following Content Security Policy directive: "style-src 'nonce-nonceynonce'". Either the 'unsafe-inline' keyword, a hash ('sha256-pckGv9YvNcB5xy+Y4fbqhyo+ib850wyiuWeNbZvLi00='), or a nonce ('nonce-...') is required to enable inline execution.
 
+CONSOLE ERROR: line 28: Refused to apply inline style because it violates the following Content Security Policy directive: "style-src 'nonce-nonceynonce'". Either the 'unsafe-inline' keyword, a hash ('sha256-47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU='), or a nonce ('nonce-...') is required to enable inline execution.
+
 CONSOLE ERROR: line 28: Refused to apply inline style because it violates the following Content Security Policy directive: "style-src 'nonce-nonceynonce'". Either the 'unsafe-inline' keyword, a hash ('sha256-QSqLgiKqPxCeZH1d3vWR+4HJOthCVhvG1P/AFaVJfR4='), or a nonce ('nonce-...') is required to enable inline execution.
 
 This is a testharness.js-based test.
diff --git a/third_party/WebKit/LayoutTests/imported/wpt/dom/nodes/MutationObserver-inner-outer-expected.txt b/third_party/WebKit/LayoutTests/imported/wpt/dom/nodes/MutationObserver-inner-outer-expected.txt
deleted file mode 100644
index 901c9c1d..0000000
--- a/third_party/WebKit/LayoutTests/imported/wpt/dom/nodes/MutationObserver-inner-outer-expected.txt
+++ /dev/null
@@ -1,6 +0,0 @@
-This is a testharness.js-based test.
-FAIL innerHTML mutation assert_equals: mutation records must match expected 2 but got 1
-PASS innerHTML with 2 children mutation 
-PASS outerHTML mutation 
-Harness: the test ran to completion.
-
diff --git a/third_party/WebKit/LayoutTests/shadow-dom/slotchange.html b/third_party/WebKit/LayoutTests/shadow-dom/slotchange.html
index 4ad226ef..30bdbe3 100644
--- a/third_party/WebKit/LayoutTests/shadow-dom/slotchange.html
+++ b/third_party/WebKit/LayoutTests/shadow-dom/slotchange.html
@@ -309,3 +309,24 @@
   n.c1.remove();
 }, "slotchange event: Fallback slot's parant slot is assinged to another slot.");
 </script>
+
+<div id="test8">
+  <div id="host1">
+    <template id="shadowroot" data-mode="open">
+      <slot id="s1"></slot>
+    </template>
+  </div>
+</div>
+
+<script>
+async_test((test) => {
+  const n = createTestTree(window.test8);
+  removeWhiteSpaceOnlyTextNodes(n.test8);
+  n.host1.innerHTML = 'hello';
+
+  window.setTimeout(() => {
+    doneIfSlotChange([n.s1], test);
+    n.host1.innerHTML = 'world';
+  }, 0);
+}, 'slotchange event: Replacing a text node with innerHTML.');
+</script>
diff --git a/third_party/WebKit/Source/bindings/core/v8/custom/V8PerformanceObserverCustom.cpp b/third_party/WebKit/Source/bindings/core/v8/custom/V8PerformanceObserverCustom.cpp
index 11d65aa..c3e8dea 100644
--- a/third_party/WebKit/Source/bindings/core/v8/custom/V8PerformanceObserverCustom.cpp
+++ b/third_party/WebKit/Source/bindings/core/v8/custom/V8PerformanceObserverCustom.cpp
@@ -54,8 +54,8 @@
   PerformanceObserverCallback* callback =
       PerformanceObserverCallback::create(scriptState, v8Callback);
 
-  PerformanceObserver* observer =
-      PerformanceObserver::create(scriptState, performance, callback);
+  PerformanceObserver* observer = PerformanceObserver::create(
+      currentExecutionContext(info.GetIsolate()), performance, callback);
 
   // TODO(bashi): Don't set private property (and remove this custom
   // constructor) when we can call setWrapperReference() correctly.
diff --git a/third_party/WebKit/Source/core/css/MediaList.cpp b/third_party/WebKit/Source/core/css/MediaList.cpp
index 4ffdd5b..bbb60db 100644
--- a/third_party/WebKit/Source/core/css/MediaList.cpp
+++ b/third_party/WebKit/Source/core/css/MediaList.cpp
@@ -65,13 +65,6 @@
   return MediaQueryParser::parseMediaQuerySet(mediaString);
 }
 
-MediaQuerySet* MediaQuerySet::createOffMainThread(const String& mediaString) {
-  if (mediaString.isEmpty())
-    return MediaQuerySet::create();
-
-  return MediaQueryParser::parseMediaQuerySet(mediaString);
-}
-
 bool MediaQuerySet::set(const String& mediaString) {
   MediaQuerySet* result = create(mediaString);
   m_queries.swap(result->m_queries);
diff --git a/third_party/WebKit/Source/core/css/MediaList.h b/third_party/WebKit/Source/core/css/MediaList.h
index 49af85a..360b92d 100644
--- a/third_party/WebKit/Source/core/css/MediaList.h
+++ b/third_party/WebKit/Source/core/css/MediaList.h
@@ -42,7 +42,6 @@
  public:
   static MediaQuerySet* create() { return new MediaQuerySet(); }
   static MediaQuerySet* create(const String& mediaString);
-  static MediaQuerySet* createOffMainThread(const String& mediaString);
 
   bool set(const String&);
   bool add(const String&);
diff --git a/third_party/WebKit/Source/core/css/MediaQuerySetTest.cpp b/third_party/WebKit/Source/core/css/MediaQuerySetTest.cpp
index 5cedc1a..600e20c 100644
--- a/third_party/WebKit/Source/core/css/MediaQuerySetTest.cpp
+++ b/third_party/WebKit/Source/core/css/MediaQuerySetTest.cpp
@@ -13,12 +13,9 @@
 typedef struct {
   const char* input;
   const char* output;
-  bool shouldWorkOnOldParser;
 } TestCase;
 
-static void testMediaQuery(TestCase test,
-                           MediaQuerySet& querySet,
-                           bool oldParser) {
+static void testMediaQuery(TestCase test, MediaQuerySet& querySet) {
   StringBuilder output;
   size_t j = 0;
   while (j < querySet.queryVector().size()) {
@@ -29,12 +26,10 @@
       break;
     output.append(", ");
   }
-  if (!oldParser || test.shouldWorkOnOldParser) {
-    if (test.output)
-      ASSERT_STREQ(test.output, output.toString().ascii().data());
-    else
-      ASSERT_STREQ(test.input, output.toString().ascii().data());
-  }
+  if (test.output)
+    ASSERT_STREQ(test.output, output.toString().ascii().data());
+  else
+    ASSERT_STREQ(test.input, output.toString().ascii().data());
 }
 
 TEST(MediaQuerySetTest, Basic) {
@@ -42,162 +37,153 @@
   // The second string represents the output string, if present.
   // Otherwise, the output string is identical to the first string.
   TestCase testCases[] = {
-      {"", 0, true},
-      {" ", "", true},
-      {"screen", 0, true},
-      {"screen and (color)", 0, true},
-      {"all and (min-width:500px)", "(min-width: 500px)", true},
-      {"all and (min-width:/*bla*/500px)", "(min-width: 500px)", true},
-      {"(min-width:500px)", "(min-width: 500px)", true},
-      {"screen and (color), projection and (color)", 0, true},
-      {"not screen and (color)", 0, true},
-      {"only screen and (color)", 0, true},
-      {"screen and (color), projection and (color)", 0, true},
-      {"aural and (device-aspect-ratio: 16/9)", 0, true},
-      {"speech and (min-device-width: 800px)", 0, true},
-      {"example", 0, true},
+      {"", nullptr},
+      {" ", ""},
+      {"screen", nullptr},
+      {"screen and (color)", nullptr},
+      {"all and (min-width:500px)", "(min-width: 500px)"},
+      {"all and (min-width:/*bla*/500px)", "(min-width: 500px)"},
+      {"(min-width:500px)", "(min-width: 500px)"},
+      {"screen and (color), projection and (color)", nullptr},
+      {"not screen and (color)", nullptr},
+      {"only screen and (color)", nullptr},
+      {"screen and (color), projection and (color)", nullptr},
+      {"aural and (device-aspect-ratio: 16/9)", nullptr},
+      {"speech and (min-device-width: 800px)", nullptr},
+      {"example", nullptr},
       {"screen and (max-weight: 3kg) and (color), (monochrome)",
-       "not all, (monochrome)", true},
-      {"(min-width: -100px)", "not all", true},
-      {"(example, all,), speech", "not all, speech", true},
-      {"&test, screen", "not all, screen", true},
-      {"print and (min-width: 25cm)", 0, true},
+       "not all, (monochrome)"},
+      {"(min-width: -100px)", "not all"},
+      {"(example, all,), speech", "not all, speech"},
+      {"&test, screen", "not all, screen"},
+      {"print and (min-width: 25cm)", nullptr},
       {"screen and (min-width: 400px) and (max-width: 700px)",
-       "screen and (max-width: 700px) and (min-width: 400px)", true},
-      {"screen and (device-width: 800px)", 0, true},
-      {"screen and (device-height: 60em)", 0, true},
-      {"screen and (device-height: 60rem)", 0, true},
-      {"screen and (device-height: 60ch)", 0, true},
-      {"screen and (device-aspect-ratio: 16/9)", 0, true},
-      {"(device-aspect-ratio: 16.0/9.0)", "not all", true},
-      {"(device-aspect-ratio: 16/ 9)", "(device-aspect-ratio: 16/9)", true},
-      {"(device-aspect-ratio: 16/\r9)", "(device-aspect-ratio: 16/9)", true},
-      {"all and (color)", "(color)", true},
-      {"all and (min-color: 1)", "(min-color: 1)", true},
-      {"all and (min-color: 1.0)", "not all", true},
-      {"all and (min-color: 2)", "(min-color: 2)", true},
-      {"all and (color-index)", "(color-index)", true},
-      {"all and (min-color-index: 1)", "(min-color-index: 1)", true},
-      {"all and (monochrome)", "(monochrome)", true},
-      {"all and (min-monochrome: 1)", "(min-monochrome: 1)", true},
-      {"all and (min-monochrome: 2)", "(min-monochrome: 2)", true},
-      {"print and (monochrome)", 0, true},
-      {"handheld and (grid) and (max-width: 15em)", 0, true},
-      {"handheld and (grid) and (max-device-height: 7em)", 0, true},
-      {"screen and (max-width: 50%)", "not all", true},
-      {"screen and (max-WIDTH: 500px)", "screen and (max-width: 500px)", true},
-      {"screen and (max-width: 24.4em)", 0, true},
-      {"screen and (max-width: 24.4EM)", "screen and (max-width: 24.4em)",
-       true},
-      {"screen and (max-width: blabla)", "not all", true},
-      {"screen and (max-width: 1)", "not all", true},
-      {"screen and (max-width: 0)", 0, true},
-      {"screen and (max-width: 1deg)", "not all", true},
+       "screen and (max-width: 700px) and (min-width: 400px)"},
+      {"screen and (device-width: 800px)", nullptr},
+      {"screen and (device-height: 60em)", nullptr},
+      {"screen and (device-height: 60rem)", nullptr},
+      {"screen and (device-height: 60ch)", nullptr},
+      {"screen and (device-aspect-ratio: 16/9)", nullptr},
+      {"(device-aspect-ratio: 16.0/9.0)", "not all"},
+      {"(device-aspect-ratio: 16/ 9)", "(device-aspect-ratio: 16/9)"},
+      {"(device-aspect-ratio: 16/\r9)", "(device-aspect-ratio: 16/9)"},
+      {"all and (color)", "(color)"},
+      {"all and (min-color: 1)", "(min-color: 1)"},
+      {"all and (min-color: 1.0)", "not all"},
+      {"all and (min-color: 2)", "(min-color: 2)"},
+      {"all and (color-index)", "(color-index)"},
+      {"all and (min-color-index: 1)", "(min-color-index: 1)"},
+      {"all and (monochrome)", "(monochrome)"},
+      {"all and (min-monochrome: 1)", "(min-monochrome: 1)"},
+      {"all and (min-monochrome: 2)", "(min-monochrome: 2)"},
+      {"print and (monochrome)", nullptr},
+      {"handheld and (grid) and (max-width: 15em)", nullptr},
+      {"handheld and (grid) and (max-device-height: 7em)", nullptr},
+      {"screen and (max-width: 50%)", "not all"},
+      {"screen and (max-WIDTH: 500px)", "screen and (max-width: 500px)"},
+      {"screen and (max-width: 24.4em)", nullptr},
+      {"screen and (max-width: 24.4EM)", "screen and (max-width: 24.4em)"},
+      {"screen and (max-width: blabla)", "not all"},
+      {"screen and (max-width: 1)", "not all"},
+      {"screen and (max-width: 0)", nullptr},
+      {"screen and (max-width: 1deg)", "not all"},
       {"handheld and (min-width: 20em), \nscreen and (min-width: 20em)",
-       "handheld and (min-width: 20em), screen and (min-width: 20em)", true},
-      {"print and (min-resolution: 300dpi)", 0, true},
-      {"print and (min-resolution: 118dpcm)", 0, true},
+       "handheld and (min-width: 20em), screen and (min-width: 20em)"},
+      {"print and (min-resolution: 300dpi)", nullptr},
+      {"print and (min-resolution: 118dpcm)", nullptr},
       {"(resolution: 0.83333333333333333333dppx)",
-       "(resolution: 0.833333333333333dppx)", true},
-      {"(resolution: 2.4dppx)", 0, true},
-      {"all and(color)", "not all", true},
-      {"all and (", "not all", true},
-      {"test;,all", "not all, all", true},
-      {"(color:20example)", "not all", false},
-      {"not braille", 0, true},
-      {",screen", "not all, screen", true},
-      {",all", "not all, all", true},
-      {",,all,,", "not all, not all, all, not all, not all", true},
-      {",,all,, ", "not all, not all, all, not all, not all", true},
+       "(resolution: 0.833333333333333dppx)"},
+      {"(resolution: 2.4dppx)", nullptr},
+      {"all and(color)", "not all"},
+      {"all and (", "not all"},
+      {"test;,all", "not all, all"},
+      {"(color:20example)", "not all"},
+      {"not braille", nullptr},
+      {",screen", "not all, screen"},
+      {",all", "not all, all"},
+      {",,all,,", "not all, not all, all, not all, not all"},
+      {",,all,, ", "not all, not all, all, not all, not all"},
       {",screen,,&invalid,,",
-       "not all, screen, not all, not all, not all, not all", true},
+       "not all, screen, not all, not all, not all, not all"},
       {",screen,,(invalid,),,",
-       "not all, screen, not all, not all, not all, not all", true},
-      {",(all,),,", "not all, not all, not all, not all", true},
-      {",", "not all, not all", true},
-      {"  ", "", true},
-      {"(color", "(color)", true},
-      {"(min-color: 2", "(min-color: 2)", true},
-      {"(orientation: portrait)", 0, true},
-      {"tv and (scan: progressive)", 0, true},
-      {"(pointer: coarse)", 0, true},
-      {"(min-orientation:portrait)", "not all", true},
-      {"all and (orientation:portrait)", "(orientation: portrait)", true},
-      {"all and (orientation:landscape)", "(orientation: landscape)", true},
+       "not all, screen, not all, not all, not all, not all"},
+      {",(all,),,", "not all, not all, not all, not all"},
+      {",", "not all, not all"},
+      {"  ", ""},
+      {"(color", "(color)"},
+      {"(min-color: 2", "(min-color: 2)"},
+      {"(orientation: portrait)", nullptr},
+      {"tv and (scan: progressive)", nullptr},
+      {"(pointer: coarse)", nullptr},
+      {"(min-orientation:portrait)", "not all"},
+      {"all and (orientation:portrait)", "(orientation: portrait)"},
+      {"all and (orientation:landscape)", "(orientation: landscape)"},
       {"NOT braille, tv AND (max-width: 200px) and (min-WIDTH: 100px) and "
        "(orientation: landscape), (color)",
        "not braille, tv and (max-width: 200px) and (min-width: 100px) and "
-       "(orientation: landscape), (color)",
-       true},
-      {"(m\\61x-width: 300px)", "(max-width: 300px)", true},
-      {"(max-width: 400\\70\\78)", "(max-width: 400px)", false},
-      {"(max-width: 500\\0070\\0078)", "(max-width: 500px)", false},
-      {"(max-width: 600\\000070\\000078)", "(max-width: 600px)", false},
+       "(orientation: landscape), (color)"},
+      {"(m\\61x-width: 300px)", "(max-width: 300px)"},
+      {"(max-width: 400\\70\\78)", "(max-width: 400px)"},
+      {"(max-width: 500\\0070\\0078)", "(max-width: 500px)"},
+      {"(max-width: 600\\000070\\000078)", "(max-width: 600px)"},
       {"(max-width: 700px), (max-width: 700px)",
-       "(max-width: 700px), (max-width: 700px)", true},
+       "(max-width: 700px), (max-width: 700px)"},
       {"(max-width: 800px()), (max-width: 800px)",
-       "not all, (max-width: 800px)", true},
-      {"(max-width: 900px(()), (max-width: 900px)", "not all", true},
+       "not all, (max-width: 800px)"},
+      {"(max-width: 900px(()), (max-width: 900px)", "not all"},
       {"(max-width: 600px(())))), (max-width: 600px)",
-       "not all, (max-width: 600px)", true},
-      {"(max-width: 500px(((((((((())))), (max-width: 500px)", "not all", true},
+       "not all, (max-width: 600px)"},
+      {"(max-width: 500px(((((((((())))), (max-width: 500px)", "not all"},
       {"(max-width: 800px[]), (max-width: 800px)",
-       "not all, (max-width: 800px)", true},
-      {"(max-width: 900px[[]), (max-width: 900px)", "not all", true},
+       "not all, (max-width: 800px)"},
+      {"(max-width: 900px[[]), (max-width: 900px)", "not all"},
       {"(max-width: 600px[[]]]]), (max-width: 600px)",
-       "not all, (max-width: 600px)", true},
-      {"(max-width: 500px[[[[[[[[[[]]]]), (max-width: 500px)", "not all", true},
+       "not all, (max-width: 600px)"},
+      {"(max-width: 500px[[[[[[[[[[]]]]), (max-width: 500px)", "not all"},
       {"(max-width: 800px{}), (max-width: 800px)",
-       "not all, (max-width: 800px)", true},
-      {"(max-width: 900px{{}), (max-width: 900px)", "not all", true},
+       "not all, (max-width: 800px)"},
+      {"(max-width: 900px{{}), (max-width: 900px)", "not all"},
       {"(max-width: 600px{{}}}}), (max-width: 600px)",
-       "not all, (max-width: 600px)", true},
-      {"(max-width: 500px{{{{{{{{{{}}}}), (max-width: 500px)", "not all", true},
-      {"[(), (max-width: 400px)", "not all", true},
-      {"[{}, (max-width: 500px)", "not all", true},
-      {"[{]}], (max-width: 900px)", "not all, (max-width: 900px)", true},
-      {"[{[]{}{{{}}}}], (max-width: 900px)", "not all, (max-width: 900px)",
-       true},
-      {"[{[}], (max-width: 900px)", "not all", true},
-      {"[({)}], (max-width: 900px)", "not all", true},
-      {"[]((), (max-width: 900px)", "not all", true},
-      {"((), (max-width: 900px)", "not all", true},
-      {"(foo(), (max-width: 900px)", "not all", true},
-      {"[](()), (max-width: 900px)", "not all, (max-width: 900px)", true},
+       "not all, (max-width: 600px)"},
+      {"(max-width: 500px{{{{{{{{{{}}}}), (max-width: 500px)", "not all"},
+      {"[(), (max-width: 400px)", "not all"},
+      {"[{}, (max-width: 500px)", "not all"},
+      {"[{]}], (max-width: 900px)", "not all, (max-width: 900px)"},
+      {"[{[]{}{{{}}}}], (max-width: 900px)", "not all, (max-width: 900px)"},
+      {"[{[}], (max-width: 900px)", "not all"},
+      {"[({)}], (max-width: 900px)", "not all"},
+      {"[]((), (max-width: 900px)", "not all"},
+      {"((), (max-width: 900px)", "not all"},
+      {"(foo(), (max-width: 900px)", "not all"},
+      {"[](()), (max-width: 900px)", "not all, (max-width: 900px)"},
       {"all an[isdfs bla())()]icalc(i)(()), (max-width: 400px)",
-       "not all, (max-width: 400px)", true},
-      {"all an[isdfs bla())(]icalc(i)(()), (max-width: 500px)", "not all",
-       true},
-      {"all an[isdfs bla())(]icalc(i)(())), (max-width: 600px)", "not all",
-       true},
+       "not all, (max-width: 400px)"},
+      {"all an[isdfs bla())(]icalc(i)(()), (max-width: 500px)", "not all"},
+      {"all an[isdfs bla())(]icalc(i)(())), (max-width: 600px)", "not all"},
       {"all an[isdfs bla())(]icalc(i)(()))], (max-width: 800px)",
-       "not all, (max-width: 800px)", true},
-      {"(max-width: '40px')", "not all", true},
-      {"('max-width': 40px)", "not all", true},
-      {"'\"'\", (max-width: 900px)", "not all", true},
-      {"'\"\"\"', (max-width: 900px)", "not all, (max-width: 900px)", true},
-      {"\"'\"', (max-width: 900px)", "not all", true},
-      {"\"'''\", (max-width: 900px)", "not all, (max-width: 900px)", true},
-      {"not not", "not all", true},
-      {"not and", "not all", true},
-      {"not only", "not all", true},
-      {"not or", "not all", true},
-      {"only not", "not all", true},
-      {"only and", "not all", true},
-      {"only only", "not all", true},
-      {"only or", "not all", true},
-      {"not (orientation)", "not all", true},
-      {"only (orientation)", "not all", true},
-      {0, 0}  // Do not remove the terminator line.
+       "not all, (max-width: 800px)"},
+      {"(max-width: '40px')", "not all"},
+      {"('max-width': 40px)", "not all"},
+      {"'\"'\", (max-width: 900px)", "not all"},
+      {"'\"\"\"', (max-width: 900px)", "not all, (max-width: 900px)"},
+      {"\"'\"', (max-width: 900px)", "not all"},
+      {"\"'''\", (max-width: 900px)", "not all, (max-width: 900px)"},
+      {"not not", "not all"},
+      {"not and", "not all"},
+      {"not only", "not all"},
+      {"not or", "not all"},
+      {"only not", "not all"},
+      {"only and", "not all"},
+      {"only only", "not all"},
+      {"only or", "not all"},
+      {"not (orientation)", "not all"},
+      {"only (orientation)", "not all"},
+      {nullptr, nullptr}  // Do not remove the terminator line.
   };
 
   for (unsigned i = 0; testCases[i].input; ++i) {
-    MediaQuerySet* oldParserQuerySet =
-        MediaQuerySet::create(testCases[i].input);
-    MediaQuerySet* threadSafeQuerySet =
-        MediaQuerySet::createOffMainThread(testCases[i].input);
-    testMediaQuery(testCases[i], *oldParserQuerySet, true);
-    testMediaQuery(testCases[i], *threadSafeQuerySet, false);
+    MediaQuerySet* querySet = MediaQuerySet::create(testCases[i].input);
+    testMediaQuery(testCases[i], *querySet);
   }
 }
 
diff --git a/third_party/WebKit/Source/core/dom/ContainerNode.cpp b/third_party/WebKit/Source/core/dom/ContainerNode.cpp
index 645e0b9f..8e46d3dc 100644
--- a/third_party/WebKit/Source/core/dom/ContainerNode.cpp
+++ b/third_party/WebKit/Source/core/dom/ContainerNode.cpp
@@ -785,6 +785,7 @@
 
 void ContainerNode::childrenChanged(const ChildrenChange& change) {
   document().incDOMTreeVersion();
+  document().notifyChangeChildren(*this);
   invalidateNodeListCachesInAncestors();
   if (change.isChildInsertion() && !childNeedsStyleRecalc()) {
     setChildNeedsStyleRecalc();
diff --git a/third_party/WebKit/Source/core/dom/Document.cpp b/third_party/WebKit/Source/core/dom/Document.cpp
index fca88932..5cc3d95 100644
--- a/third_party/WebKit/Source/core/dom/Document.cpp
+++ b/third_party/WebKit/Source/core/dom/Document.cpp
@@ -5730,9 +5730,8 @@
   m_frame->console().addMessage(consoleMessage);
 }
 
-// FIXME(crbug.com/305497): This should be removed after
-// ExecutionContext-LocalDOMWindow migration.
-void Document::postTask(const WebTraceLocation& location,
+void Document::postTask(TaskType,
+                        const WebTraceLocation& location,
                         std::unique_ptr<ExecutionContextTask> task,
                         const String& taskNameForInstrumentation) {
   m_taskRunner->postTask(location, std::move(task), taskNameForInstrumentation);
diff --git a/third_party/WebKit/Source/core/dom/Document.h b/third_party/WebKit/Source/core/dom/Document.h
index 38cbd58e..62bceac 100644
--- a/third_party/WebKit/Source/core/dom/Document.h
+++ b/third_party/WebKit/Source/core/dom/Document.h
@@ -990,9 +990,9 @@
   bool isDNSPrefetchEnabled() const { return m_isDNSPrefetchEnabled; }
   void parseDNSPrefetchControlHeader(const String&);
 
-  // FIXME(crbug.com/305497): This should be removed once LocalDOMWindow is an
-  // ExecutionContext.
-  void postTask(const WebTraceLocation&,
+  using ExecutionContext::postTask;
+  void postTask(TaskType,
+                const WebTraceLocation&,
                 std::unique_ptr<ExecutionContextTask>,
                 const String& taskNameForInstrumentation = emptyString())
       override;  // Executes the task on context's thread asynchronously.
@@ -1229,7 +1229,6 @@
   void notifyResizeForViewportUnits();
 
   void updateActiveStyle();
-  void updateStyleInvalidationIfNeeded();
 
   DECLARE_VIRTUAL_TRACE();
 
@@ -1363,6 +1362,7 @@
   void updateUseShadowTreesIfNeeded();
   void evaluateMediaQueryListIfNeeded();
 
+  void updateStyleInvalidationIfNeeded();
   void updateStyle();
   void notifyLayoutTreeOfSubtreeChanges();
 
diff --git a/third_party/WebKit/Source/core/dom/DocumentTest.cpp b/third_party/WebKit/Source/core/dom/DocumentTest.cpp
index 0554841b..5aa5712d 100644
--- a/third_party/WebKit/Source/core/dom/DocumentTest.cpp
+++ b/third_party/WebKit/Source/core/dom/DocumentTest.cpp
@@ -114,6 +114,10 @@
     return m_contextDestroyedCalledCounter;
   }
 
+  const HeapVector<Member<const ContainerNode>>& childrenChangedNodes() const {
+    return m_childrenChangedNodes;
+  }
+
   const HeapVector<Member<MergeTextNodesRecord>>& mergeTextNodesRecords()
       const {
     return m_mergeTextNodesRecords;
@@ -141,6 +145,7 @@
  private:
   // Implement |SynchronousMutationObserver| member functions.
   void contextDestroyed() final;
+  void didChangeChildren(const ContainerNode&) final;
   void didMergeTextNodes(Text&, unsigned) final;
   void didSplitTextNode(const Text&) final;
   void didUpdateCharacterData(CharacterData*,
@@ -151,6 +156,7 @@
   void nodeWillBeRemoved(Node&) final;
 
   int m_contextDestroyedCalledCounter = 0;
+  HeapVector<Member<const ContainerNode>> m_childrenChangedNodes;
   HeapVector<Member<MergeTextNodesRecord>> m_mergeTextNodesRecords;
   HeapVector<Member<ContainerNode>> m_removedChildrenNodes;
   HeapVector<Member<Node>> m_removedNodes;
@@ -169,6 +175,11 @@
   ++m_contextDestroyedCalledCounter;
 }
 
+void TestSynchronousMutationObserver::didChangeChildren(
+    const ContainerNode& container) {
+  m_childrenChangedNodes.append(&container);
+}
+
 void TestSynchronousMutationObserver::didMergeTextNodes(Text& node,
                                                         unsigned offset) {
   m_mergeTextNodesRecords.append(new MergeTextNodesRecord(&node, offset));
@@ -197,6 +208,7 @@
 }
 
 DEFINE_TRACE(TestSynchronousMutationObserver) {
+  visitor->trace(m_childrenChangedNodes);
   visitor->trace(m_mergeTextNodesRecords);
   visitor->trace(m_removedChildrenNodes);
   visitor->trace(m_removedNodes);
@@ -469,6 +481,21 @@
   EXPECT_EQ(observer.countContextDestroyedCalled(), 1);
 }
 
+TEST_F(DocumentTest, SynchronousMutationNotifieAppendChild) {
+  auto& observer = *new TestSynchronousMutationObserver(document());
+  document().body()->appendChild(document().createTextNode("a123456789"));
+  ASSERT_EQ(1u, observer.childrenChangedNodes().size());
+  EXPECT_EQ(document().body(), observer.childrenChangedNodes()[0]);
+}
+
+TEST_F(DocumentTest, SynchronousMutationNotifieInsertBefore) {
+  auto& observer = *new TestSynchronousMutationObserver(document());
+  document().documentElement()->insertBefore(
+      document().createTextNode("a123456789"), document().body());
+  ASSERT_EQ(1u, observer.childrenChangedNodes().size());
+  EXPECT_EQ(document().documentElement(), observer.childrenChangedNodes()[0]);
+}
+
 TEST_F(DocumentTest, SynchronousMutationNotifierMergeTextNodes) {
   auto& observer = *new TestSynchronousMutationObserver(document());
 
@@ -486,6 +513,26 @@
   EXPECT_EQ(observer.mergeTextNodesRecords()[0]->m_offset, 10u);
 }
 
+TEST_F(DocumentTest, SynchronousMutationNotifieRemoveChild) {
+  auto& observer = *new TestSynchronousMutationObserver(document());
+  document().documentElement()->removeChild(document().body());
+  ASSERT_EQ(1u, observer.childrenChangedNodes().size());
+  EXPECT_EQ(document().documentElement(), observer.childrenChangedNodes()[0]);
+}
+
+TEST_F(DocumentTest, SynchronousMutationNotifieReplaceChild) {
+  auto& observer = *new TestSynchronousMutationObserver(document());
+  Element* const replacedNode = document().body();
+  document().documentElement()->replaceChild(document().createElement("div"),
+                                             document().body());
+  ASSERT_EQ(2u, observer.childrenChangedNodes().size());
+  EXPECT_EQ(document().documentElement(), observer.childrenChangedNodes()[0]);
+  EXPECT_EQ(document().documentElement(), observer.childrenChangedNodes()[1]);
+
+  ASSERT_EQ(1u, observer.removedNodes().size());
+  EXPECT_EQ(replacedNode, observer.removedNodes()[0]);
+}
+
 TEST_F(DocumentTest, SynchronousMutationNotifierSplitTextNode) {
   auto& observer = *new TestSynchronousMutationObserver(document());
 
diff --git a/third_party/WebKit/Source/core/dom/ExecutionContext.cpp b/third_party/WebKit/Source/core/dom/ExecutionContext.cpp
index 6dd66ea..bafadfdc 100644
--- a/third_party/WebKit/Source/core/dom/ExecutionContext.cpp
+++ b/third_party/WebKit/Source/core/dom/ExecutionContext.cpp
@@ -29,6 +29,7 @@
 
 #include "bindings/core/v8/SourceLocation.h"
 #include "core/dom/ExecutionContextTask.h"
+#include "core/dom/TaskRunnerHelper.h"
 #include "core/events/ErrorEvent.h"
 #include "core/events/EventTarget.h"
 #include "core/fetch/MemoryCache.h"
@@ -164,6 +165,13 @@
   return virtualCompleteURL(url);
 }
 
+void ExecutionContext::postTask(const WebTraceLocation& location,
+                                std::unique_ptr<ExecutionContextTask> task,
+                                const String& taskNameForInstrumentation) {
+  postTask(TaskType::Unspecified, location, std::move(task),
+           taskNameForInstrumentation);
+}
+
 void ExecutionContext::allowWindowInteraction() {
   ++m_windowInteractionTokens;
 }
diff --git a/third_party/WebKit/Source/core/dom/ExecutionContext.h b/third_party/WebKit/Source/core/dom/ExecutionContext.h
index e0c259d..899b3d2b 100644
--- a/third_party/WebKit/Source/core/dom/ExecutionContext.h
+++ b/third_party/WebKit/Source/core/dom/ExecutionContext.h
@@ -53,6 +53,7 @@
 class LocalDOMWindow;
 class PublicURLManager;
 class SecurityOrigin;
+enum class TaskType : unsigned;
 
 class CORE_EXPORT ExecutionContext : public ContextLifecycleNotifier,
                                      public Supplementable<ExecutionContext> {
@@ -94,9 +95,13 @@
   virtual String userAgent() const = 0;
   // Executes the task on context's thread asynchronously.
   virtual void postTask(
+      TaskType,
       const WebTraceLocation&,
       std::unique_ptr<ExecutionContextTask>,
       const String& taskNameForInstrumentation = emptyString()) = 0;
+  void postTask(const WebTraceLocation&,
+                std::unique_ptr<ExecutionContextTask>,
+                const String& taskNameForInstrumentation = emptyString());
 
   // Gets the DOMTimerCoordinator which maintains the "active timer
   // list" of tasks created by setTimeout and setInterval. The
@@ -127,6 +132,10 @@
 
   void suspendScheduledTasks();
   void resumeScheduledTasks();
+
+  // TODO(haraken): Remove these methods by making the customers inherit from
+  // ActiveDOMObject. ActiveDOMObject is a standard way to observe context
+  // suspension/resumption.
   virtual bool tasksNeedSuspension() { return false; }
   virtual void tasksWereSuspended() {}
   virtual void tasksWereResumed() {}
diff --git a/third_party/WebKit/Source/core/dom/SynchronousMutationNotifier.cpp b/third_party/WebKit/Source/core/dom/SynchronousMutationNotifier.cpp
index b045d71..8084bdc9 100644
--- a/third_party/WebKit/Source/core/dom/SynchronousMutationNotifier.cpp
+++ b/third_party/WebKit/Source/core/dom/SynchronousMutationNotifier.cpp
@@ -11,6 +11,12 @@
 
 SynchronousMutationNotifier::SynchronousMutationNotifier() = default;
 
+void SynchronousMutationNotifier::notifyChangeChildren(
+    const ContainerNode& container) {
+  for (SynchronousMutationObserver* observer : m_observers)
+    observer->didChangeChildren(container);
+}
+
 void SynchronousMutationNotifier::notifyMergeTextNodes(Text& node,
                                                        unsigned offset) {
   for (SynchronousMutationObserver* observer : m_observers)
diff --git a/third_party/WebKit/Source/core/dom/SynchronousMutationNotifier.h b/third_party/WebKit/Source/core/dom/SynchronousMutationNotifier.h
index a54b8e24..b8005d1 100644
--- a/third_party/WebKit/Source/core/dom/SynchronousMutationNotifier.h
+++ b/third_party/WebKit/Source/core/dom/SynchronousMutationNotifier.h
@@ -23,6 +23,7 @@
  public:
   // TODO(yosin): We will have |notifyXXX()| functions defined in
   // |SynchronousMutationObserver|.
+  void notifyChangeChildren(const ContainerNode&);
   void notifyMergeTextNodes(Text&, unsigned);
   void notifySplitTextNode(const Text&);
   void notifyUpdateCharacterData(CharacterData*,
diff --git a/third_party/WebKit/Source/core/dom/SynchronousMutationObserver.cpp b/third_party/WebKit/Source/core/dom/SynchronousMutationObserver.cpp
index 3aee82b3..4add663 100644
--- a/third_party/WebKit/Source/core/dom/SynchronousMutationObserver.cpp
+++ b/third_party/WebKit/Source/core/dom/SynchronousMutationObserver.cpp
@@ -12,6 +12,7 @@
 SynchronousMutationObserver::SynchronousMutationObserver()
     : LifecycleObserver(nullptr) {}
 
+void SynchronousMutationObserver::didChangeChildren(const ContainerNode&) {}
 void SynchronousMutationObserver::didMergeTextNodes(Text&, unsigned) {}
 void SynchronousMutationObserver::didSplitTextNode(const Text&) {}
 void SynchronousMutationObserver::didUpdateCharacterData(CharacterData*,
diff --git a/third_party/WebKit/Source/core/dom/SynchronousMutationObserver.h b/third_party/WebKit/Source/core/dom/SynchronousMutationObserver.h
index bb6a20e..b52fb0b 100644
--- a/third_party/WebKit/Source/core/dom/SynchronousMutationObserver.h
+++ b/third_party/WebKit/Source/core/dom/SynchronousMutationObserver.h
@@ -39,6 +39,9 @@
   //  - didInsertText(Node*, unsigned offset, unsigned length);
   //  - didRemoveText(Node*, unsigned offset, unsigned length);
 
+  // Called after child nodes changed.
+  virtual void didChangeChildren(const ContainerNode&);
+
   // TODO(yosin): We should use |const Text& oldNode|.
   // Called after characters in |oldNode| is appended at |offset| in
   // |oldNdoe->previousSibling()|.
diff --git a/third_party/WebKit/Source/core/dom/TaskRunnerHelper.cpp b/third_party/WebKit/Source/core/dom/TaskRunnerHelper.cpp
index 0667f7b0..377d45d 100644
--- a/third_party/WebKit/Source/core/dom/TaskRunnerHelper.cpp
+++ b/third_party/WebKit/Source/core/dom/TaskRunnerHelper.cpp
@@ -35,11 +35,11 @@
       return frame ? frame->frameScheduler()->loadingTaskRunner()
                    : Platform::current()->currentThread()->getWebTaskRunner();
     case TaskType::Unthrottled:
+    case TaskType::Unspecified:
       return frame ? frame->frameScheduler()->unthrottledTaskRunner()
                    : Platform::current()->currentThread()->getWebTaskRunner();
-    default:
-      NOTREACHED();
   }
+  NOTREACHED();
   return nullptr;
 }
 
diff --git a/third_party/WebKit/Source/core/dom/TaskRunnerHelper.h b/third_party/WebKit/Source/core/dom/TaskRunnerHelper.h
index 0cdddb8..ffd59c3 100644
--- a/third_party/WebKit/Source/core/dom/TaskRunnerHelper.h
+++ b/third_party/WebKit/Source/core/dom/TaskRunnerHelper.h
@@ -42,6 +42,10 @@
   // Tasks that must not be throttled should be posted here, but the usage
   // should be very limited.
   Unthrottled,
+
+  // Tasks that any other TaskType is not assigned to. This should be
+  // transitional and should be removed.
+  Unspecified,
 };
 
 // HashTraits for TaskType.
diff --git a/third_party/WebKit/Source/core/editing/DOMSelection.cpp b/third_party/WebKit/Source/core/editing/DOMSelection.cpp
index 91d8dbe..e7c2c90 100644
--- a/third_party/WebKit/Source/core/editing/DOMSelection.cpp
+++ b/third_party/WebKit/Source/core/editing/DOMSelection.cpp
@@ -272,8 +272,17 @@
     return;
   }
 
-  if (!baseNode || !extentNode)
+  // TODO(editing-dev): Behavior on where base or extent is null is still
+  // under discussion: https://github.com/w3c/selection-api/issues/72
+  if (!baseNode) {
     UseCounter::count(frame(), UseCounter::SelectionSetBaseAndExtentNull);
+    frame()->selection().clear();
+    return;
+  }
+  if (!extentNode) {
+    UseCounter::count(frame(), UseCounter::SelectionSetBaseAndExtentNull);
+    extentOffset = 0;
+  }
 
   if (!isValidForPosition(baseNode) || !isValidForPosition(extentNode))
     return;
diff --git a/third_party/WebKit/Source/core/editing/InputMethodController.cpp b/third_party/WebKit/Source/core/editing/InputMethodController.cpp
index 92edae8..bae3cea 100644
--- a/third_party/WebKit/Source/core/editing/InputMethodController.cpp
+++ b/third_party/WebKit/Source/core/editing/InputMethodController.cpp
@@ -84,9 +84,11 @@
   DCHECK(compositionType ==
              TypingCommand::TextCompositionType::TextCompositionUpdate ||
          compositionType ==
-             TypingCommand::TextCompositionType::TextCompositionConfirm)
+             TypingCommand::TextCompositionType::TextCompositionConfirm ||
+         compositionType ==
+             TypingCommand::TextCompositionType::TextCompositionCancel)
       << "compositionType should be TextCompositionUpdate or "
-         "TextCompositionConfirm, but got "
+         "TextCompositionConfirm  or TextCompositionCancel, but got "
       << static_cast<int>(compositionType);
   if (!frame.document())
     return;
@@ -126,6 +128,7 @@
                                 compositionType);
       break;
     case TypingCommand::TextCompositionType::TextCompositionConfirm:
+    case TypingCommand::TextCompositionType::TextCompositionCancel:
       // TODO(chongz): Use TypingCommand::insertText after TextEvent was
       // removed. (Removed from spec since 2012)
       // See TextEvent.idl.
@@ -379,7 +382,7 @@
   dispatchCompositionUpdateEvent(frame(), emptyString());
   insertTextDuringCompositionWithEvents(
       frame(), emptyString(), 0,
-      TypingCommand::TextCompositionType::TextCompositionConfirm);
+      TypingCommand::TextCompositionType::TextCompositionCancel);
   // Event handler might destroy document.
   if (!isAvailable())
     return;
diff --git a/third_party/WebKit/Source/core/editing/commands/TypingCommand.h b/third_party/WebKit/Source/core/editing/commands/TypingCommand.h
index f1259d0..a21fa517 100644
--- a/third_party/WebKit/Source/core/editing/commands/TypingCommand.h
+++ b/third_party/WebKit/Source/core/editing/commands/TypingCommand.h
@@ -45,7 +45,8 @@
   enum TextCompositionType {
     TextCompositionNone,
     TextCompositionUpdate,
-    TextCompositionConfirm
+    TextCompositionConfirm,
+    TextCompositionCancel
   };
 
   enum Option {
diff --git a/third_party/WebKit/Source/core/editing/serializers/Serialization.cpp b/third_party/WebKit/Source/core/editing/serializers/Serialization.cpp
index bf02c4e..c91ae783 100644
--- a/third_party/WebKit/Source/core/editing/serializers/Serialization.cpp
+++ b/third_party/WebKit/Source/core/editing/serializers/Serialization.cpp
@@ -713,13 +713,6 @@
     return;
   }
 
-  // FIXME: This is wrong if containerNode->firstChild() has more than one ref!
-  if (containerNode->hasOneTextChild() && fragment->hasOneTextChild()) {
-    toText(containerNode->firstChild())
-        ->setData(toText(fragment->firstChild())->data());
-    return;
-  }
-
   // FIXME: No need to replace the child it is a text node and its contents are
   // already == text.
   if (containerNode->hasOneChild()) {
diff --git a/third_party/WebKit/Source/core/html/parser/HTMLPreloadScanner.cpp b/third_party/WebKit/Source/core/html/parser/HTMLPreloadScanner.cpp
index fc48a38..49e2abc7 100644
--- a/third_party/WebKit/Source/core/html/parser/HTMLPreloadScanner.cpp
+++ b/third_party/WebKit/Source/core/html/parser/HTMLPreloadScanner.cpp
@@ -126,8 +126,7 @@
 
 static bool mediaAttributeMatches(const MediaValuesCached& mediaValues,
                                   const String& attributeValue) {
-  MediaQuerySet* mediaQueries =
-      MediaQuerySet::createOffMainThread(attributeValue);
+  MediaQuerySet* mediaQueries = MediaQuerySet::create(attributeValue);
   MediaQueryEvaluator mediaQueryEvaluator(mediaValues);
   return mediaQueryEvaluator.eval(mediaQueries);
 }
diff --git a/third_party/WebKit/Source/core/layout/LayoutBlock.cpp b/third_party/WebKit/Source/core/layout/LayoutBlock.cpp
index 1fdd612..f114f6e 100644
--- a/third_party/WebKit/Source/core/layout/LayoutBlock.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutBlock.cpp
@@ -1887,15 +1887,6 @@
   return createAnonymousWithParentAndDisplay(parent, style()->display());
 }
 
-LayoutUnit LayoutBlock::nextPageLogicalTop(LayoutUnit logicalOffset) const {
-  LayoutUnit pageLogicalHeight = pageLogicalHeightForOffset(logicalOffset);
-  if (!pageLogicalHeight)
-    return logicalOffset;
-
-  return logicalOffset + pageRemainingLogicalHeightForOffset(
-                             logicalOffset, AssociateWithLatterPage);
-}
-
 void LayoutBlock::paginatedContentWasLaidOut(
     LayoutUnit logicalBottomOffsetAfterPagination) {
   if (LayoutFlowThread* flowThread = flowThreadContainingBlock())
diff --git a/third_party/WebKit/Source/core/layout/LayoutBlock.h b/third_party/WebKit/Source/core/layout/LayoutBlock.h
index dd75d49..47922010 100644
--- a/third_party/WebKit/Source/core/layout/LayoutBlock.h
+++ b/third_party/WebKit/Source/core/layout/LayoutBlock.h
@@ -511,9 +511,6 @@
     return pageLogicalHeightForOffset(LayoutUnit());
   }
 
-  // Returns the logical offset at the top of the next page, for a given offset.
-  LayoutUnit nextPageLogicalTop(LayoutUnit logicalOffset) const;
-
   // Paginated content inside this block was laid out.
   // |logicalBottomOffsetAfterPagination| is the logical bottom offset of the
   // child content after applying any forced or unforced breaks as needed.
diff --git a/third_party/WebKit/Source/core/layout/LayoutBlockFlow.cpp b/third_party/WebKit/Source/core/layout/LayoutBlockFlow.cpp
index cb24181e..c16002b9 100644
--- a/third_party/WebKit/Source/core/layout/LayoutBlockFlow.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutBlockFlow.cpp
@@ -815,7 +815,7 @@
   // Now determine the correct ypos based off examination of collapsing margin
   // values.
   LayoutUnit logicalTopBeforeClear =
-      collapseMargins(child, marginInfo, childIsSelfCollapsing,
+      collapseMargins(child, layoutInfo, childIsSelfCollapsing,
                       childDiscardMarginBefore, childDiscardMarginAfter);
 
   // Now check for clear.
@@ -1599,11 +1599,38 @@
                                        childAfterPositive, childAfterNegative);
 }
 
+LayoutUnit LayoutBlockFlow::adjustedMarginBeforeForPagination(
+    const LayoutBox& child,
+    LayoutUnit logicalTopMarginEdge,
+    LayoutUnit logicalTopBorderEdge,
+    const BlockChildrenLayoutInfo& layoutInfo) const {
+  LayoutUnit effectiveMargin = logicalTopBorderEdge - logicalTopMarginEdge;
+  DCHECK(isPageLogicalHeightKnown());
+  if (effectiveMargin <= LayoutUnit())
+    return effectiveMargin;
+  // If margins would pull us past the top of the next fragmentainer, then we
+  // need to pull back and let the margins collapse into the fragmentainer
+  // boundary. If we're at a fragmentainer boundary, and there's no forced break
+  // involved, collapse the margin with the boundary we're at. Otherwise,
+  // preserve the margin at the top of the fragmentainer, but collapse it with
+  // the next fragmentainer boundary, since no margin should ever live in more
+  // than one fragmentainer.
+  PageBoundaryRule rule = AssociateWithLatterPage;
+  if (!child.needsForcedBreakBefore(layoutInfo.previousBreakAfterValue()) &&
+      offsetFromLogicalTopOfFirstPage() + logicalTopMarginEdge > LayoutUnit())
+    rule = AssociateWithFormerPage;
+  LayoutUnit remainingSpace =
+      pageRemainingLogicalHeightForOffset(logicalTopMarginEdge, rule);
+  return std::min(effectiveMargin, remainingSpace);
+}
+
 LayoutUnit LayoutBlockFlow::collapseMargins(LayoutBox& child,
-                                            MarginInfo& marginInfo,
+                                            BlockChildrenLayoutInfo& layoutInfo,
                                             bool childIsSelfCollapsing,
                                             bool childDiscardMarginBefore,
                                             bool childDiscardMarginAfter) {
+  MarginInfo& marginInfo = layoutInfo.marginInfo();
+
   // The child discards the before margin when the the after margin has discard
   // in the case of a self collapsing block.
   childDiscardMarginBefore = childDiscardMarginBefore ||
@@ -1765,14 +1792,11 @@
       marginInfo.setHasMarginAfterQuirk(hasMarginAfterQuirk(&child));
   }
 
-  // If margins would pull us past the top of the next page, then we need to
-  // pull back and pretend like the margins collapsed into the page edge.
-  LayoutState* layoutState = view()->layoutState();
-  if (layoutState->isPaginated() && isPageLogicalHeightKnown() &&
-      logicalTop > beforeCollapseLogicalTop) {
+  if (view()->layoutState()->isPaginated() && isPageLogicalHeightKnown()) {
     LayoutUnit oldLogicalTop = logicalTop;
-    logicalTop =
-        std::min(logicalTop, nextPageLogicalTop(beforeCollapseLogicalTop));
+    LayoutUnit margin = adjustedMarginBeforeForPagination(
+        child, beforeCollapseLogicalTop, logicalTop, layoutInfo);
+    logicalTop = beforeCollapseLogicalTop + margin;
     setLogicalHeight(logicalHeight() + (logicalTop - oldLogicalTop));
   }
 
@@ -2063,13 +2087,12 @@
           std::max(marginInfo.negativeMargin(), negativeMarginBefore);
   }
 
-  // Adjust logicalTopEstimate down to the next page if the margins are so large
-  // that we don't fit on the current page.
   LayoutState* layoutState = view()->layoutState();
-  if (layoutState->isPaginated() && isPageLogicalHeightKnown() &&
-      logicalTopEstimate > logicalHeight())
-    logicalTopEstimate =
-        std::min(logicalTopEstimate, nextPageLogicalTop(logicalHeight()));
+  if (layoutState->isPaginated() && isPageLogicalHeightKnown()) {
+    LayoutUnit margin = adjustedMarginBeforeForPagination(
+        child, logicalHeight(), logicalTopEstimate, layoutInfo);
+    logicalTopEstimate = logicalHeight() + margin;
+  }
 
   logicalTopEstimate += getClearDelta(&child, logicalTopEstimate);
 
diff --git a/third_party/WebKit/Source/core/layout/LayoutBlockFlow.h b/third_party/WebKit/Source/core/layout/LayoutBlockFlow.h
index 13872c04..3ae25bc 100644
--- a/third_party/WebKit/Source/core/layout/LayoutBlockFlow.h
+++ b/third_party/WebKit/Source/core/layout/LayoutBlockFlow.h
@@ -778,8 +778,14 @@
     return maxPositiveMarginAfter() - maxNegativeMarginAfter();
   }
 
+  LayoutUnit adjustedMarginBeforeForPagination(
+      const LayoutBox&,
+      LayoutUnit logicalTopMarginEdge,
+      LayoutUnit logicalTopBorderEdge,
+      const BlockChildrenLayoutInfo&) const;
+
   LayoutUnit collapseMargins(LayoutBox& child,
-                             MarginInfo&,
+                             BlockChildrenLayoutInfo&,
                              bool childIsSelfCollapsing,
                              bool childDiscardMarginBefore,
                              bool childDiscardMarginAfter);
diff --git a/third_party/WebKit/Source/core/layout/line/BreakingContextInlineHeaders.h b/third_party/WebKit/Source/core/layout/line/BreakingContextInlineHeaders.h
index 0fd887de..75cb21f4 100644
--- a/third_party/WebKit/Source/core/layout/line/BreakingContextInlineHeaders.h
+++ b/third_party/WebKit/Source/core/layout/line/BreakingContextInlineHeaders.h
@@ -161,6 +161,7 @@
                           bool breakAll,
                           int& nextBreakablePositionForBreakAll);
   bool rewindToMidWordBreak(WordMeasurement&, int end, float width);
+  bool canMidWordBreakBefore(LineLayoutText);
   bool rewindToFirstMidWordBreak(LineLayoutText,
                                  const ComputedStyle&,
                                  const Font&,
@@ -760,6 +761,28 @@
   return true;
 }
 
+ALWAYS_INLINE bool BreakingContext::canMidWordBreakBefore(LineLayoutText text) {
+  // No break opportunities at the beginning of a line.
+  if (!m_width.currentWidth())
+    return false;
+  // If this text node is not the first child of an inline, the parent and the
+  // preivous have the same style.
+  if (text.previousSibling())
+    return true;
+  // Element boundaries belong to the parent of the element.
+  // TODO(kojii): Not all cases of element boundaries are supported yet.
+  // crbug.com/282134
+  if (LineLayoutItem element = text.parent()) {
+    if (LineLayoutItem parent = element.parent()) {
+      const ComputedStyle& parentStyle = parent.styleRef();
+      return parentStyle.autoWrap() &&
+             ((parentStyle.breakWords() && !m_width.committedWidth()) ||
+              parentStyle.wordBreak() == BreakAllWordBreak);
+    }
+  }
+  return false;
+}
+
 ALWAYS_INLINE bool BreakingContext::rewindToFirstMidWordBreak(
     LineLayoutText text,
     const ComputedStyle& style,
@@ -767,21 +790,24 @@
     bool breakAll,
     WordMeasurement& wordMeasurement) {
   int start = wordMeasurement.startOffset;
-  int end;
+  int end = canMidWordBreakBefore(text) ? start : start + 1;
   if (breakAll) {
     LazyLineBreakIterator lineBreakIterator(text.text(), style.locale());
-    end = -1;
-    lineBreakIterator.isBreakable(start + 1, end, LineBreakType::BreakAll);
-    if (end < 0)
+    int nextBreakable = -1;
+    lineBreakIterator.isBreakable(end, nextBreakable, LineBreakType::BreakAll);
+    if (nextBreakable < 0)
       return false;
-  } else {
-    end = start + 1;
+    end = nextBreakable;
   }
   if (end >= wordMeasurement.endOffset)
     return false;
 
   float width = textWidth(text, start, end - start, font,
                           m_width.currentWidth(), m_collapseWhiteSpace);
+  // If the first break opportunity doesn't fit, and if there's a break
+  // opportunity in previous runs, break at the opportunity.
+  if (!m_width.fitsOnLine(width) && m_width.committedWidth())
+    return false;
   return rewindToMidWordBreak(wordMeasurement, end, width);
 }
 
@@ -795,23 +821,27 @@
   int len = wordMeasurement.endOffset - start;
   if (!len)
     return false;
-  if (m_width.availableWidth() <= LayoutUnit::epsilon())
+  float xPosToBreak = m_width.availableWidth() - m_width.currentWidth();
+  if (xPosToBreak <= LayoutUnit::epsilon()) {
+    // There were no space left. Skip computing how many characters can fit.
     return rewindToFirstMidWordBreak(text, style, font, breakAll,
                                      wordMeasurement);
+  }
 
   TextRun run = constructTextRun(font, text, start, len, style);
   run.setTabSize(!m_collapseWhiteSpace, style.getTabSize());
   run.setXPos(m_width.currentWidth());
 
   // TODO(kojii): should be replaced with safe-to-break when hb is ready.
-  float x =
-      m_width.availableWidth() + LayoutUnit::epsilon() - m_width.currentWidth();
+  xPosToBreak += LayoutUnit::epsilon();
   if (run.rtl())
-    x = wordMeasurement.width - x;
-  len = font.offsetForPosition(run, x, false);
-  if (!len && !m_width.currentWidth())
+    xPosToBreak = wordMeasurement.width - xPosToBreak;
+  len = font.offsetForPosition(run, xPosToBreak, false);
+  if (!len) {
+    // No characters can fit in the available space.
     return rewindToFirstMidWordBreak(text, style, font, breakAll,
                                      wordMeasurement);
+  }
 
   int end = start + len;
   if (breakAll) {
diff --git a/third_party/WebKit/Source/core/loader/resource/FontResource.cpp b/third_party/WebKit/Source/core/loader/resource/FontResource.cpp
index d17d3a9..15569e19 100644
--- a/third_party/WebKit/Source/core/loader/resource/FontResource.cpp
+++ b/third_party/WebKit/Source/core/loader/resource/FontResource.cpp
@@ -110,7 +110,7 @@
 }
 
 void FontResource::startLoadLimitTimers() {
-  CHECK(isLoading());
+  DCHECK(isLoading());
   DCHECK_EQ(m_loadLimitState, LoadNotStarted);
   m_loadLimitState = UnderLimit;
   m_fontLoadShortLimitTimer.startOneShot(fontLoadWaitShortLimitSec,
@@ -144,7 +144,6 @@
 }
 
 void FontResource::fontLoadShortLimitCallback(TimerBase*) {
-  CHECK(isLoading());
   if (!isLoading())
     return;
   DCHECK_EQ(m_loadLimitState, UnderLimit);
@@ -155,7 +154,6 @@
 }
 
 void FontResource::fontLoadLongLimitCallback(TimerBase*) {
-  CHECK(isLoading());
   if (!isLoading())
     return;
   DCHECK_EQ(m_loadLimitState, ShortLimitExceeded);
diff --git a/third_party/WebKit/Source/core/testing/NullExecutionContext.cpp b/third_party/WebKit/Source/core/testing/NullExecutionContext.cpp
index 6041b8d5..e25dd0a 100644
--- a/third_party/WebKit/Source/core/testing/NullExecutionContext.cpp
+++ b/third_party/WebKit/Source/core/testing/NullExecutionContext.cpp
@@ -28,7 +28,8 @@
       m_isSecureContext(true),
       m_queue(new NullEventQueue()) {}
 
-void NullExecutionContext::postTask(const WebTraceLocation&,
+void NullExecutionContext::postTask(TaskType,
+                                    const WebTraceLocation&,
                                     std::unique_ptr<ExecutionContextTask>,
                                     const String&) {}
 
diff --git a/third_party/WebKit/Source/core/testing/NullExecutionContext.h b/third_party/WebKit/Source/core/testing/NullExecutionContext.h
index 987c02d..a4617fff 100644
--- a/third_party/WebKit/Source/core/testing/NullExecutionContext.h
+++ b/third_party/WebKit/Source/core/testing/NullExecutionContext.h
@@ -29,6 +29,7 @@
   String userAgent() const override { return String(); }
 
   void postTask(
+      TaskType,
       const WebTraceLocation&,
       std::unique_ptr<ExecutionContextTask>,
       const String& taskNameForInstrumentation = emptyString()) override;
diff --git a/third_party/WebKit/Source/core/timing/PerformanceBaseTest.cpp b/third_party/WebKit/Source/core/timing/PerformanceBaseTest.cpp
index fa6848f..1ff271cd 100644
--- a/third_party/WebKit/Source/core/timing/PerformanceBaseTest.cpp
+++ b/third_party/WebKit/Source/core/timing/PerformanceBaseTest.cpp
@@ -40,7 +40,8 @@
         v8::Function::New(scriptState->context(), nullptr).ToLocalChecked();
     m_base = new TestPerformanceBase();
     m_cb = PerformanceObserverCallback::create(scriptState, callback);
-    m_observer = PerformanceObserver::create(scriptState, m_base, m_cb);
+    m_observer = PerformanceObserver::create(scriptState->getExecutionContext(),
+                                             m_base, m_cb);
   }
 
   void SetUp() override {
diff --git a/third_party/WebKit/Source/core/timing/PerformanceObserver.cpp b/third_party/WebKit/Source/core/timing/PerformanceObserver.cpp
index b1c8982..a0148f0 100644
--- a/third_party/WebKit/Source/core/timing/PerformanceObserver.cpp
+++ b/third_party/WebKit/Source/core/timing/PerformanceObserver.cpp
@@ -17,17 +17,17 @@
 namespace blink {
 
 PerformanceObserver* PerformanceObserver::create(
-    ScriptState* scriptState,
+    ExecutionContext* executionContext,
     PerformanceBase* performance,
     PerformanceObserverCallback* callback) {
   ASSERT(isMainThread());
-  return new PerformanceObserver(scriptState, performance, callback);
+  return new PerformanceObserver(executionContext, performance, callback);
 }
 
-PerformanceObserver::PerformanceObserver(ScriptState* scriptState,
+PerformanceObserver::PerformanceObserver(ExecutionContext* executionContext,
                                          PerformanceBase* performance,
                                          PerformanceObserverCallback* callback)
-    : m_scriptState(scriptState),
+    : m_executionContext(executionContext),
       m_callback(this, callback),
       m_performance(performance),
       m_filterOptions(PerformanceEntry::Invalid),
@@ -77,8 +77,7 @@
 }
 
 bool PerformanceObserver::shouldBeSuspended() const {
-  return m_scriptState->getExecutionContext() &&
-         m_scriptState->getExecutionContext()->activeDOMObjectsAreSuspended();
+  return m_executionContext->activeDOMObjectsAreSuspended();
 }
 
 void PerformanceObserver::deliver() {
@@ -95,6 +94,7 @@
 }
 
 DEFINE_TRACE(PerformanceObserver) {
+  visitor->trace(m_executionContext);
   visitor->trace(m_callback);
   visitor->trace(m_performance);
   visitor->trace(m_performanceEntries);
diff --git a/third_party/WebKit/Source/core/timing/PerformanceObserver.h b/third_party/WebKit/Source/core/timing/PerformanceObserver.h
index 1219062..cea36e1 100644
--- a/third_party/WebKit/Source/core/timing/PerformanceObserver.h
+++ b/third_party/WebKit/Source/core/timing/PerformanceObserver.h
@@ -13,12 +13,12 @@
 
 namespace blink {
 
+class ExecutionContext;
 class ExceptionState;
 class PerformanceBase;
 class PerformanceObserver;
 class PerformanceObserverCallback;
 class PerformanceObserverInit;
-class ScriptState;
 
 using PerformanceEntryVector = HeapVector<Member<PerformanceEntry>>;
 
@@ -31,7 +31,7 @@
   friend class PerformanceObserverTest;
 
  public:
-  static PerformanceObserver* create(ScriptState*,
+  static PerformanceObserver* create(ExecutionContext*,
                                      PerformanceBase*,
                                      PerformanceObserverCallback*);
   static void resumeSuspendedObservers();
@@ -45,13 +45,13 @@
   DECLARE_TRACE_WRAPPERS();
 
  private:
-  PerformanceObserver(ScriptState*,
+  PerformanceObserver(ExecutionContext*,
                       PerformanceBase*,
                       PerformanceObserverCallback*);
   void deliver();
   bool shouldBeSuspended() const;
 
-  RefPtr<ScriptState> m_scriptState;
+  Member<ExecutionContext> m_executionContext;
   TraceWrapperMember<PerformanceObserverCallback> m_callback;
   WeakMember<PerformanceBase> m_performance;
   PerformanceEntryVector m_performanceEntries;
diff --git a/third_party/WebKit/Source/core/timing/PerformanceObserverTest.cpp b/third_party/WebKit/Source/core/timing/PerformanceObserverTest.cpp
index bebd97c..16aa20c 100644
--- a/third_party/WebKit/Source/core/timing/PerformanceObserverTest.cpp
+++ b/third_party/WebKit/Source/core/timing/PerformanceObserverTest.cpp
@@ -29,7 +29,8 @@
         v8::Function::New(scriptState->context(), nullptr).ToLocalChecked();
     m_base = new MockPerformanceBase();
     m_cb = PerformanceObserverCallback::create(scriptState, callback);
-    m_observer = PerformanceObserver::create(scriptState, m_base, m_cb);
+    m_observer = PerformanceObserver::create(scriptState->getExecutionContext(),
+                                             m_base, m_cb);
   }
 
   bool isRegistered() { return m_observer->m_isRegistered; }
diff --git a/third_party/WebKit/Source/core/workers/ThreadedWorkletGlobalScope.cpp b/third_party/WebKit/Source/core/workers/ThreadedWorkletGlobalScope.cpp
index 0be4de5..f5be192 100644
--- a/third_party/WebKit/Source/core/workers/ThreadedWorkletGlobalScope.cpp
+++ b/third_party/WebKit/Source/core/workers/ThreadedWorkletGlobalScope.cpp
@@ -41,6 +41,7 @@
 }
 
 void ThreadedWorkletGlobalScope::postTask(
+    TaskType,
     const WebTraceLocation& location,
     std::unique_ptr<ExecutionContextTask> task,
     const String& taskNameForInstrumentation) {
diff --git a/third_party/WebKit/Source/core/workers/ThreadedWorkletGlobalScope.h b/third_party/WebKit/Source/core/workers/ThreadedWorkletGlobalScope.h
index 37c27d4..0b1a5dc 100644
--- a/third_party/WebKit/Source/core/workers/ThreadedWorkletGlobalScope.h
+++ b/third_party/WebKit/Source/core/workers/ThreadedWorkletGlobalScope.h
@@ -20,7 +20,8 @@
   // ExecutionContext
   bool isThreadedWorkletGlobalScope() const final { return true; }
   bool isContextThread() const final;
-  void postTask(const WebTraceLocation&,
+  void postTask(TaskType,
+                const WebTraceLocation&,
                 std::unique_ptr<ExecutionContextTask>,
                 const String& taskNameForInstrumentation) final;
   void addConsoleMessage(ConsoleMessage*) final;
diff --git a/third_party/WebKit/Source/core/workers/ThreadedWorkletObjectProxy.cpp b/third_party/WebKit/Source/core/workers/ThreadedWorkletObjectProxy.cpp
index 37f2e08f..72a392b 100644
--- a/third_party/WebKit/Source/core/workers/ThreadedWorkletObjectProxy.cpp
+++ b/third_party/WebKit/Source/core/workers/ThreadedWorkletObjectProxy.cpp
@@ -4,14 +4,12 @@
 
 #include "core/workers/ThreadedWorkletObjectProxy.h"
 
-#include "bindings/core/v8/SerializedScriptValue.h"
-#include "bindings/core/v8/SourceLocation.h"
-#include "core/dom/Document.h"
 #include "core/dom/ExecutionContext.h"
-#include "core/dom/ExecutionContextTask.h"
 #include "core/inspector/ConsoleMessage.h"
 #include "core/workers/ParentFrameTaskRunners.h"
 #include "core/workers/ThreadedWorkletMessagingProxy.h"
+#include "platform/CrossThreadFunctional.h"
+#include "platform/WebTaskRunner.h"
 #include "wtf/Functional.h"
 #include "wtf/PtrUtil.h"
 #include <memory>
@@ -33,18 +31,18 @@
     MessageLevel level,
     const String& message,
     SourceLocation* location) {
-  // TODO(nhiroki): Replace this with getParentFrameTaskRunners().
-  // (https://crbug.com/667310)
-  getExecutionContext()->postTask(
-      BLINK_FROM_HERE, createCrossThreadTask(
-                           &ThreadedWorkletMessagingProxy::reportConsoleMessage,
-                           m_messagingProxyWeakPtr, source, level, message,
-                           passed(location->clone())));
+  getParentFrameTaskRunners()
+      ->get(TaskType::Internal)
+      ->postTask(
+          BLINK_FROM_HERE,
+          crossThreadBind(&ThreadedWorkletMessagingProxy::reportConsoleMessage,
+                          m_messagingProxyWeakPtr, source, level, message,
+                          passed(location->clone())));
 }
 
 void ThreadedWorkletObjectProxy::postMessageToPageInspector(
     const String& message) {
-  DCHECK(getExecutionContext()->isDocument());
+  DCHECK(m_messagingProxyWeakPtr->getExecutionContext()->isDocument());
   // The TaskType of Inspector tasks need to be Unthrottled because they need to
   // run even on a suspended page.
   getParentFrameTaskRunners()
@@ -61,31 +59,26 @@
 }
 
 void ThreadedWorkletObjectProxy::didCloseWorkerGlobalScope() {
-  // TODO(nhiroki): Replace this with getParentFrameTaskRunners().
-  // (https://crbug.com/667310)
-  getExecutionContext()->postTask(
-      BLINK_FROM_HERE, createCrossThreadTask(
-                           &ThreadedWorkletMessagingProxy::terminateGlobalScope,
-                           m_messagingProxyWeakPtr));
+  getParentFrameTaskRunners()
+      ->get(TaskType::Internal)
+      ->postTask(
+          BLINK_FROM_HERE,
+          crossThreadBind(&ThreadedWorkletMessagingProxy::terminateGlobalScope,
+                          m_messagingProxyWeakPtr));
 }
 
 void ThreadedWorkletObjectProxy::didTerminateWorkerThread() {
   // This will terminate the MessagingProxy.
-  // TODO(nhiroki): Replace this with getParentFrameTaskRunners().
-  // (https://crbug.com/667310)
-  getExecutionContext()->postTask(
-      BLINK_FROM_HERE,
-      createCrossThreadTask(
-          &ThreadedWorkletMessagingProxy::workerThreadTerminated,
-          m_messagingProxyWeakPtr));
+  getParentFrameTaskRunners()
+      ->get(TaskType::Internal)
+      ->postTask(BLINK_FROM_HERE,
+                 crossThreadBind(
+                     &ThreadedWorkletMessagingProxy::workerThreadTerminated,
+                     m_messagingProxyWeakPtr));
 }
 
 ThreadedWorkletObjectProxy::ThreadedWorkletObjectProxy(
     const WeakPtr<ThreadedWorkletMessagingProxy>& messagingProxyWeakPtr)
     : m_messagingProxyWeakPtr(messagingProxyWeakPtr) {}
 
-ExecutionContext* ThreadedWorkletObjectProxy::getExecutionContext() const {
-  return m_messagingProxyWeakPtr->getExecutionContext();
-}
-
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/workers/ThreadedWorkletObjectProxy.h b/third_party/WebKit/Source/core/workers/ThreadedWorkletObjectProxy.h
index 0b4bfe83..0ce5f6e 100644
--- a/third_party/WebKit/Source/core/workers/ThreadedWorkletObjectProxy.h
+++ b/third_party/WebKit/Source/core/workers/ThreadedWorkletObjectProxy.h
@@ -12,7 +12,6 @@
 
 namespace blink {
 
-class ExecutionContext;
 class ThreadedWorkletMessagingProxy;
 
 // A proxy to talk to the parent worklet object. This object is created on the
@@ -49,8 +48,6 @@
   ThreadedWorkletObjectProxy(const WeakPtr<ThreadedWorkletMessagingProxy>&);
 
  private:
-  ExecutionContext* getExecutionContext() const;
-
   // No guarantees about the lifetimes of tasks posted by this proxy wrt the
   // ThreadedWorkletMessagingProxy so a weak pointer must be used when posting
   // the tasks.
diff --git a/third_party/WebKit/Source/core/workers/WorkerGlobalScope.cpp b/third_party/WebKit/Source/core/workers/WorkerGlobalScope.cpp
index dbeaca5..608ede32 100644
--- a/third_party/WebKit/Source/core/workers/WorkerGlobalScope.cpp
+++ b/third_party/WebKit/Source/core/workers/WorkerGlobalScope.cpp
@@ -272,7 +272,8 @@
   m_scriptController->disableEval(errorMessage);
 }
 
-void WorkerGlobalScope::postTask(const WebTraceLocation& location,
+void WorkerGlobalScope::postTask(TaskType,
+                                 const WebTraceLocation& location,
                                  std::unique_ptr<ExecutionContextTask> task,
                                  const String& taskNameForInstrumentation) {
   thread()->postTask(location, std::move(task),
diff --git a/third_party/WebKit/Source/core/workers/WorkerGlobalScope.h b/third_party/WebKit/Source/core/workers/WorkerGlobalScope.h
index ec2c76f..81eaca5 100644
--- a/third_party/WebKit/Source/core/workers/WorkerGlobalScope.h
+++ b/third_party/WebKit/Source/core/workers/WorkerGlobalScope.h
@@ -126,7 +126,8 @@
   bool isContextThread() const final;
   void disableEval(const String& errorMessage) final;
   String userAgent() const final { return m_userAgent; }
-  void postTask(const WebTraceLocation&,
+  void postTask(TaskType,
+                const WebTraceLocation&,
                 std::unique_ptr<ExecutionContextTask>,
                 const String& taskNameForInstrumentation) final;
   DOMTimerCoordinator* timers() final { return &m_timers; }
diff --git a/third_party/WebKit/Source/core/workers/WorkletGlobalScope.h b/third_party/WebKit/Source/core/workers/WorkletGlobalScope.h
index df0192e..d527e3c 100644
--- a/third_party/WebKit/Source/core/workers/WorkletGlobalScope.h
+++ b/third_party/WebKit/Source/core/workers/WorkletGlobalScope.h
@@ -74,7 +74,8 @@
     NOTREACHED();
     return nullptr;
   }  // WorkletGlobalScopes don't have timers.
-  void postTask(const WebTraceLocation&,
+  void postTask(TaskType,
+                const WebTraceLocation&,
                 std::unique_ptr<ExecutionContextTask>,
                 const String&) override {
     // TODO(ikilpatrick): implement.
diff --git a/third_party/WebKit/Source/web/TextFinder.cpp b/third_party/WebKit/Source/web/TextFinder.cpp
index f674f1ce..150b2c2a 100644
--- a/third_party/WebKit/Source/web/TextFinder.cpp
+++ b/third_party/WebKit/Source/web/TextFinder.cpp
@@ -70,10 +70,9 @@
   static DeferredScopeStringMatches* create(TextFinder* textFinder,
                                             int identifier,
                                             const WebString& searchText,
-                                            const WebFindOptions& options,
-                                            bool reset) {
+                                            const WebFindOptions& options) {
     return new DeferredScopeStringMatches(textFinder, identifier, searchText,
-                                          options, reset);
+                                          options);
   }
 
   DEFINE_INLINE_TRACE() { visitor->trace(m_textFinder); }
@@ -84,20 +83,18 @@
   DeferredScopeStringMatches(TextFinder* textFinder,
                              int identifier,
                              const WebString& searchText,
-                             const WebFindOptions& options,
-                             bool reset)
+                             const WebFindOptions& options)
       : m_timer(this, &DeferredScopeStringMatches::doTimeout),
         m_textFinder(textFinder),
         m_identifier(identifier),
         m_searchText(searchText),
-        m_options(options),
-        m_reset(reset) {
+        m_options(options) {
     m_timer.startOneShot(0.0, BLINK_FROM_HERE);
   }
 
   void doTimeout(TimerBase*) {
-    m_textFinder->callScopeStringMatches(this, m_identifier, m_searchText,
-                                         m_options, m_reset);
+    m_textFinder->resumeScopingStringMatches(m_identifier, m_searchText,
+                                             m_options);
   }
 
   Timer<DeferredScopeStringMatches> m_timer;
@@ -105,7 +102,6 @@
   const int m_identifier;
   const WebString m_searchText;
   const WebFindOptions m_options;
-  const bool m_reset;
 };
 
 bool TextFinder::find(int identifier,
@@ -263,45 +259,45 @@
   }
 }
 
+void TextFinder::startScopingStringMatches(int identifier,
+                                           const WebString& searchText,
+                                           const WebFindOptions& options) {
+  cancelPendingScopingEffort();
+
+  // This is a brand new search, so we need to reset everything.
+  // Scoping is just about to begin.
+  m_scopingInProgress = true;
+
+  // Need to keep the current identifier locally in order to finish the
+  // request in case the frame is detached during the process.
+  m_findRequestIdentifier = identifier;
+
+  // Clear highlighting for this frame.
+  unmarkAllTextMatches();
+
+  // Clear the tickmarks and results cache.
+  clearFindMatchesCache();
+
+  // Clear the total match count and increment markers version.
+  resetMatchCount();
+
+  // Clear the counters from last operation.
+  m_lastMatchCount = 0;
+  m_nextInvalidateAfter = 0;
+  m_resumeScopingFromRange = nullptr;
+
+  // The view might be null on detached frames.
+  LocalFrame* frame = ownerFrame().frame();
+  if (frame && frame->page())
+    m_frameScoping = true;
+
+  // Now, defer scoping until later to allow find operation to finish quickly.
+  scopeStringMatchesSoon(identifier, searchText, options);
+}
+
 void TextFinder::scopeStringMatches(int identifier,
                                     const WebString& searchText,
-                                    const WebFindOptions& options,
-                                    bool reset) {
-  // TODO(dglazkov): The reset/continue cases need to be untangled into two
-  // separate functions. This collation of logic is unnecessary and adds to
-  // overall complexity of the code.
-  if (reset) {
-    // This is a brand new search, so we need to reset everything.
-    // Scoping is just about to begin.
-    m_scopingInProgress = true;
-
-    // Need to keep the current identifier locally in order to finish the
-    // request in case the frame is detached during the process.
-    m_findRequestIdentifier = identifier;
-
-    // Clear highlighting for this frame.
-    unmarkAllTextMatches();
-
-    // Clear the tickmarks and results cache.
-    clearFindMatchesCache();
-
-    // Clear the counters from last operation.
-    m_lastMatchCount = 0;
-    m_nextInvalidateAfter = 0;
-    m_resumeScopingFromRange = nullptr;
-
-    // The view might be null on detached frames.
-    LocalFrame* frame = ownerFrame().frame();
-    if (frame && frame->page())
-      m_frameScoping = true;
-
-    // Now, defer scoping until later to allow find operation to finish quickly.
-    scopeStringMatchesSoon(
-        identifier, searchText, options,
-        false);  // false means just reset, so don't do it again.
-    return;
-  }
-
+                                    const WebFindOptions& options) {
   if (!shouldScopeMatches(searchText, options)) {
     finishCurrentScopingEffort(identifier);
     return;
@@ -429,8 +425,7 @@
       invalidateIfNecessary();
 
     // Scoping effort ran out of time, lets ask for another time-slice.
-    scopeStringMatchesSoon(identifier, searchText, options,
-                           false);  // don't reset.
+    scopeStringMatchesSoon(identifier, searchText, options);
     return;                         // Done for now, resume work later.
   }
 
@@ -456,9 +451,10 @@
 }
 
 void TextFinder::cancelPendingScopingEffort() {
-  for (DeferredScopeStringMatches* deferredWork : m_deferredScopingWork)
-    deferredWork->dispose();
-  m_deferredScopingWork.clear();
+  if (m_deferredScopingWork) {
+    m_deferredScopingWork->dispose();
+    m_deferredScopingWork.clear();
+  }
 
   m_activeMatchIndex = -1;
 
@@ -731,21 +727,18 @@
 
 void TextFinder::scopeStringMatchesSoon(int identifier,
                                         const WebString& searchText,
-                                        const WebFindOptions& options,
-                                        bool reset) {
-  m_deferredScopingWork.append(DeferredScopeStringMatches::create(
-      this, identifier, searchText, options, reset));
+                                        const WebFindOptions& options) {
+  DCHECK_EQ(m_deferredScopingWork, nullptr);
+  m_deferredScopingWork =
+      DeferredScopeStringMatches::create(this, identifier, searchText, options);
 }
 
-void TextFinder::callScopeStringMatches(DeferredScopeStringMatches* caller,
-                                        int identifier,
-                                        const WebString& searchText,
-                                        const WebFindOptions& options,
-                                        bool reset) {
-  size_t index = m_deferredScopingWork.find(caller);
-  m_deferredScopingWork.remove(index);
+void TextFinder::resumeScopingStringMatches(int identifier,
+                                            const WebString& searchText,
+                                            const WebFindOptions& options) {
+  m_deferredScopingWork.clear();
 
-  scopeStringMatches(identifier, searchText, options, reset);
+  scopeStringMatches(identifier, searchText, options);
 }
 
 void TextFinder::invalidateIfNecessary() {
diff --git a/third_party/WebKit/Source/web/TextFinder.h b/third_party/WebKit/Source/web/TextFinder.h
index 6c04b1e..ea5dd0a 100644
--- a/third_party/WebKit/Source/web/TextFinder.h
+++ b/third_party/WebKit/Source/web/TextFinder.h
@@ -72,20 +72,11 @@
   void findMatchRects(WebVector<WebFloatRect>&);
   int selectNearestFindMatch(const WebFloatPoint&, WebRect* selectionRect);
 
-  // Counts how many times a particular string occurs within the frame.  It
-  // also retrieves the location of the string and updates a vector in the
-  // frame so that tick-marks and highlighting can be drawn.  This function
-  // does its work asynchronously, by running for a certain time-slice and
-  // then scheduling itself (co-operative multitasking) to be invoked later
-  // (repeating the process until all matches have been found).  This allows
-  // multiple frames to be searched at the same time and provides a way to
-  // cancel at any time (see cancelPendingScopingEffort).  The parameter
-  // searchText specifies what to look for and |reset| signals whether this is
-  // a brand new request or a continuation of the last scoping effort.
-  void scopeStringMatches(int identifier,
-                          const WebString& searchText,
-                          const WebFindOptions&,
-                          bool reset);
+  // Starts brand new scoping request: resets the scoping state and
+  // asyncronously calls scopeStringMatches().
+  void startScopingStringMatches(int identifier,
+                                 const WebString& searchText,
+                                 const WebFindOptions&);
 
   // Cancels any outstanding requests for scoping string matches on the frame.
   void cancelPendingScopingEffort();
@@ -187,18 +178,28 @@
   // appropriate.
   void finishCurrentScopingEffort(int identifier);
 
+  // Counts how many times a particular string occurs within the frame.  It
+  // also retrieves the location of the string and updates a vector in the
+  // frame so that tick-marks and highlighting can be drawn.  This function
+  // does its work asynchronously, by running for a certain time-slice and
+  // then scheduling itself (co-operative multitasking) to be invoked later
+  // (repeating the process until all matches have been found).  This allows
+  // multiple frames to be searched at the same time and provides a way to
+  // cancel at any time (see cancelPendingScopingEffort).  The parameter
+  // searchText specifies what to look for.
+  void scopeStringMatches(int identifier,
+                          const WebString& searchText,
+                          const WebFindOptions&);
+
   // Queue up a deferred call to scopeStringMatches.
   void scopeStringMatchesSoon(int identifier,
                               const WebString& searchText,
-                              const WebFindOptions&,
-                              bool reset);
+                              const WebFindOptions&);
 
   // Called by a DeferredScopeStringMatches instance.
-  void callScopeStringMatches(DeferredScopeStringMatches*,
-                              int identifier,
-                              const WebString& searchText,
-                              const WebFindOptions&,
-                              bool reset);
+  void resumeScopingStringMatches(int identifier,
+                                  const WebString& searchText,
+                                  const WebFindOptions&);
 
   // Determines whether to invalidate the content area and scrollbar.
   void invalidateIfNecessary();
@@ -254,8 +255,8 @@
   // and the frame area.
   int m_nextInvalidateAfter;
 
-  // A list of all of the pending calls to scopeStringMatches.
-  HeapVector<Member<DeferredScopeStringMatches>> m_deferredScopingWork;
+  // Pending call to scopeStringMatches.
+  Member<DeferredScopeStringMatches> m_deferredScopingWork;
 
   // Version number incremented whenever this frame's find-in-page match
   // markers change.
diff --git a/third_party/WebKit/Source/web/WebLocalFrameImpl.cpp b/third_party/WebKit/Source/web/WebLocalFrameImpl.cpp
index 7c317d7..7ae12c4a 100644
--- a/third_party/WebKit/Source/web/WebLocalFrameImpl.cpp
+++ b/third_party/WebKit/Source/web/WebLocalFrameImpl.cpp
@@ -2125,14 +2125,9 @@
     return;
   }
 
-  // Scoping effort begins.
-  ensureTextFinder().resetMatchCount();
-  textFinder()->cancelPendingScopingEffort();
-
   // Start a new scoping request. If the scoping function determines that it
   // needs to scope, it will defer until later.
-  textFinder()->scopeStringMatches(identifier, searchText, options,
-                                   true /* reset */);
+  ensureTextFinder().startScopingStringMatches(identifier, searchText, options);
 }
 
 bool WebLocalFrameImpl::find(int identifier,
diff --git a/third_party/WebKit/Source/web/tests/TextFinderTest.cpp b/third_party/WebKit/Source/web/tests/TextFinderTest.cpp
index 25a588b..534f3d87 100644
--- a/third_party/WebKit/Source/web/tests/TextFinderTest.cpp
+++ b/third_party/WebKit/Source/web/tests/TextFinderTest.cpp
@@ -308,7 +308,7 @@
   WebFindOptions findOptions;  // Default.
 
   textFinder().resetMatchCount();
-  textFinder().scopeStringMatches(identifier, searchText, findOptions, true);
+  textFinder().startScopingStringMatches(identifier, searchText, findOptions);
   while (textFinder().scopingInProgress())
     runPendingTasks();
 
@@ -320,6 +320,32 @@
   EXPECT_EQ(findInPageRect(textNode, 14, textNode, 20), matchRects[1]);
 }
 
+TEST_F(TextFinderTest, ScopeTextMatchesRepeated) {
+  document().body()->setInnerHTML("XXXXFindMeYYYYfindmeZZZZ");
+  document().updateStyleAndLayout();
+
+  Node* textNode = document().body()->firstChild();
+
+  int identifier = 0;
+  WebString searchText1(String("XFindMe"));
+  WebString searchText2(String("FindMe"));
+  WebFindOptions findOptions;  // Default.
+
+  textFinder().resetMatchCount();
+  textFinder().startScopingStringMatches(identifier, searchText1, findOptions);
+  textFinder().startScopingStringMatches(identifier, searchText2, findOptions);
+  while (textFinder().scopingInProgress())
+    runPendingTasks();
+
+  // Only searchText2 should be highlighted.
+  EXPECT_EQ(2, textFinder().totalMatchCount());
+  WebVector<WebFloatRect> matchRects;
+  textFinder().findMatchRects(matchRects);
+  ASSERT_EQ(2u, matchRects.size());
+  EXPECT_EQ(findInPageRect(textNode, 4, textNode, 10), matchRects[0]);
+  EXPECT_EQ(findInPageRect(textNode, 14, textNode, 20), matchRects[1]);
+}
+
 TEST_F(TextFinderTest, ScopeTextMatchesWithShadowDOM) {
   document().body()->setInnerHTML("<b>FOO</b><i>foo</i>");
   ShadowRoot* shadowRoot = document().body()->createShadowRootInternal(
@@ -336,7 +362,7 @@
   WebFindOptions findOptions;  // Default.
 
   textFinder().resetMatchCount();
-  textFinder().scopeStringMatches(identifier, searchText, findOptions, true);
+  textFinder().startScopingStringMatches(identifier, searchText, findOptions);
   while (textFinder().scopingInProgress())
     runPendingTasks();
 
@@ -366,7 +392,7 @@
   WebFindOptions findOptions;  // Default.
 
   textFinder().resetMatchCount();
-  textFinder().scopeStringMatches(identifier, searchText, findOptions, true);
+  textFinder().startScopingStringMatches(identifier, searchText, findOptions);
   while (textFinder().scopingInProgress())
     runPendingTasks();
 
@@ -389,7 +415,7 @@
   WebFindOptions findOptions;  // Default.
 
   textFinder().resetMatchCount();
-  textFinder().scopeStringMatches(identifier, searchText, findOptions, true);
+  textFinder().startScopingStringMatches(identifier, searchText, findOptions);
   while (textFinder().scopingInProgress())
     runPendingTasks();
 
@@ -412,7 +438,7 @@
   WebFindOptions findOptions;  // Default.
 
   textFinder().resetMatchCount();
-  textFinder().scopeStringMatches(identifier, searchText, findOptions, true);
+  textFinder().startScopingStringMatches(identifier, searchText, findOptions);
   while (textFinder().scopingInProgress())
     runPendingTasks();
 
@@ -436,7 +462,7 @@
   bool activeNow;
 
   textFinder().resetMatchCount();
-  textFinder().scopeStringMatches(identifier, searchText, findOptions, true);
+  textFinder().startScopingStringMatches(identifier, searchText, findOptions);
   while (textFinder().scopingInProgress())
     runPendingTasks();
 
@@ -466,7 +492,7 @@
   findOptions.findNext = false;
   textFinder().resetMatchCount();
   textFinder().cancelPendingScopingEffort();
-  textFinder().scopeStringMatches(identifier, searchText, findOptions, true);
+  textFinder().startScopingStringMatches(identifier, searchText, findOptions);
   while (textFinder().scopingInProgress())
     runPendingTasks();
   EXPECT_EQ(2, textFinder().totalMatchCount());
@@ -526,7 +552,8 @@
 
   // There will be only one iteration before timeout, because increment
   // of the TimeProxyPlatform timer is greater than timeout threshold.
-  textFinder().scopeStringMatches(identifier, searchPattern, findOptions, true);
+  textFinder().startScopingStringMatches(identifier, searchPattern,
+                                         findOptions);
   while (textFinder().scopingInProgress())
     runPendingTasks();
 
diff --git a/third_party/WebKit/Source/web/tests/WebFrameTest.cpp b/third_party/WebKit/Source/web/tests/WebFrameTest.cpp
index ade7eb5..97c161a 100644
--- a/third_party/WebKit/Source/web/tests/WebFrameTest.cpp
+++ b/third_party/WebKit/Source/web/tests/WebFrameTest.cpp
@@ -4647,9 +4647,10 @@
   mainFrame->ensureTextFinder().resetMatchCount();
 
   for (WebLocalFrameImpl* frame = mainFrame; frame;
-       frame = static_cast<WebLocalFrameImpl*>(frame->traverseNext()))
-    frame->ensureTextFinder().scopeStringMatches(kFindIdentifier, searchText,
-                                                 options, true);
+       frame = static_cast<WebLocalFrameImpl*>(frame->traverseNext())) {
+    frame->ensureTextFinder().startScopingStringMatches(kFindIdentifier,
+                                                        searchText, options);
+  }
 
   runPendingTasks();
   EXPECT_TRUE(client.findResultsAreReady());
@@ -4710,18 +4711,20 @@
   mainFrame->ensureTextFinder().resetMatchCount();
 
   for (WebLocalFrameImpl* frame = mainFrame; frame;
-       frame = static_cast<WebLocalFrameImpl*>(frame->traverseNext()))
-    frame->ensureTextFinder().scopeStringMatches(kFindIdentifier, searchText,
-                                                 options, true);
+       frame = static_cast<WebLocalFrameImpl*>(frame->traverseNext())) {
+    frame->ensureTextFinder().startScopingStringMatches(kFindIdentifier,
+                                                        searchText, options);
+  }
 
   runPendingTasks();
   EXPECT_TRUE(mainFrame->find(kFindIdentifier, searchText, options, false));
   mainFrame->stopFinding(WebLocalFrame::StopFindActionClearSelection);
 
   for (WebLocalFrameImpl* frame = mainFrame; frame;
-       frame = static_cast<WebLocalFrameImpl*>(frame->traverseNext()))
-    frame->ensureTextFinder().scopeStringMatches(kFindIdentifier, searchText,
-                                                 options, true);
+       frame = static_cast<WebLocalFrameImpl*>(frame->traverseNext())) {
+    frame->ensureTextFinder().startScopingStringMatches(kFindIdentifier,
+                                                        searchText, options);
+  }
 
   runPendingTasks();
   EXPECT_TRUE(client.findResultsAreReady());
@@ -4734,9 +4737,10 @@
   mainFrame->ensureTextFinder().resetMatchCount();
 
   for (WebLocalFrameImpl* frame = mainFrame; frame;
-       frame = static_cast<WebLocalFrameImpl*>(frame->traverseNext()))
-    frame->ensureTextFinder().scopeStringMatches(kFindIdentifier, searchTextNew,
-                                                 options, true);
+       frame = static_cast<WebLocalFrameImpl*>(frame->traverseNext())) {
+    frame->ensureTextFinder().startScopingStringMatches(kFindIdentifier,
+                                                        searchTextNew, options);
+  }
 
   runPendingTasks();
   EXPECT_TRUE(client.findResultsAreReady());
@@ -4775,9 +4779,10 @@
   mainFrame->ensureTextFinder().resetMatchCount();
 
   for (WebLocalFrameImpl* frame = mainFrame; frame;
-       frame = static_cast<WebLocalFrameImpl*>(frame->traverseNext()))
-    frame->ensureTextFinder().scopeStringMatches(kFindIdentifier, searchText,
-                                                 options, true);
+       frame = static_cast<WebLocalFrameImpl*>(frame->traverseNext())) {
+    frame->ensureTextFinder().startScopingStringMatches(kFindIdentifier,
+                                                        searchText, options);
+  }
 
   runPendingTasks();
   EXPECT_TRUE(client.findResultsAreReady());
@@ -4814,9 +4819,10 @@
   mainFrame->ensureTextFinder().resetMatchCount();
 
   for (WebLocalFrameImpl* frame = mainFrame; frame;
-       frame = static_cast<WebLocalFrameImpl*>(frame->traverseNext()))
-    frame->ensureTextFinder().scopeStringMatches(kFindIdentifier, searchText,
-                                                 options, true);
+       frame = static_cast<WebLocalFrameImpl*>(frame->traverseNext())) {
+    frame->ensureTextFinder().startScopingStringMatches(kFindIdentifier,
+                                                        searchText, options);
+  }
 
   runPendingTasks();
   EXPECT_TRUE(client.findResultsAreReady());
@@ -4850,12 +4856,13 @@
   mainFrame->ensureTextFinder().resetMatchCount();
 
   for (WebLocalFrameImpl* frame = mainFrame; frame;
-       frame = static_cast<WebLocalFrameImpl*>(frame->traverseNext()))
-    frame->ensureTextFinder().scopeStringMatches(kFindIdentifier, searchText,
-                                                 options, true);
+       frame = static_cast<WebLocalFrameImpl*>(frame->traverseNext())) {
+    frame->ensureTextFinder().startScopingStringMatches(kFindIdentifier,
+                                                        searchText, options);
+  }
 
-  // The first scopeStringMatches will have reset the state. Detach before it
-  // actually scopes.
+  // The first startScopingStringMatches will have reset the state. Detach
+  // before it actually scopes.
   removeElementById(mainFrame, "frame");
 
   runPendingTasks();
@@ -4910,8 +4917,8 @@
   EXPECT_TRUE(mainFrame->find(kFindIdentifier, searchText, options, false));
 
   mainFrame->ensureTextFinder().resetMatchCount();
-  mainFrame->ensureTextFinder().scopeStringMatches(kFindIdentifier, searchText,
-                                                   options, true);
+  mainFrame->ensureTextFinder().startScopingStringMatches(kFindIdentifier,
+                                                          searchText, options);
 
   runPendingTasks();
   EXPECT_TRUE(client.findResultsAreReady());
@@ -4962,8 +4969,8 @@
   bool activeNow;
 
   frame->ensureTextFinder().resetMatchCount();
-  frame->ensureTextFinder().scopeStringMatches(findIdentifier, searchText,
-                                               options, true);
+  frame->ensureTextFinder().startScopingStringMatches(findIdentifier,
+                                                      searchText, options);
   runPendingTasks();
   EXPECT_TRUE(client.findResultsAreReady());
 
diff --git a/third_party/WebKit/public/platform/WebURLResponse.h b/third_party/WebKit/public/platform/WebURLResponse.h
index 00315e70..52cf175 100644
--- a/third_party/WebKit/public/platform/WebURLResponse.h
+++ b/third_party/WebKit/public/platform/WebURLResponse.h
@@ -98,7 +98,7 @@
                        const WebString& issuer,
                        double validFrom,
                        double validTo,
-                       WebVector<WebString>& certificate,
+                       const WebVector<WebString>& certificate,
                        const SignedCertificateTimestampList& sctList)
         : protocol(protocol),
           keyExchange(keyExchange),
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index 589b88cf..b9c9aae 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -82260,6 +82260,9 @@
   <int value="54" label="Device identification missing">
     Device model or serial number missing from VPD.
   </int>
+  <int value="55" label="AD policy fetch fail">
+    Active Directory policy fetch failed.
+  </int>
 </enum>
 
 <enum name="EnterprisePolicies" type="int">
diff --git a/ui/views/test/event_generator_delegate_mac.mm b/ui/views/test/event_generator_delegate_mac.mm
index bc17c37..6fe8fb3 100644
--- a/ui/views/test/event_generator_delegate_mac.mm
+++ b/ui/views/test/event_generator_delegate_mac.mm
@@ -401,6 +401,13 @@
       [NSApp sendEvent:ns_event];
       break;
     case Target::WINDOW:
+      // -[NSApp sendEvent:] sends -performKeyEquivalent: if Command or Control
+      // modifiers are pressed. Emulate that behavior.
+      if ([ns_event type] == NSKeyDown &&
+          ([ns_event modifierFlags] & (NSControlKeyMask | NSCommandKeyMask)) &&
+          [window_ performKeyEquivalent:ns_event])
+        break;  // Handled by performKeyEquivalent:.
+
       [window_ sendEvent:ns_event];
       break;
     case Target::WIDGET: