diff --git a/DEPS b/DEPS
index 1386369..49187f5 100644
--- a/DEPS
+++ b/DEPS
@@ -78,7 +78,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
-  'v8_revision': 'f33ef1564b32db30ef95d33373d488c38b711a75',
+  'v8_revision': '917ba9699109b1356a84ae261f740a1be3c1523a',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling swarming_client
   # and whatever else without interference from each other.
@@ -130,7 +130,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling catapult
   # and whatever else without interference from each other.
-  'catapult_revision': 'd624b3ced2c81d4fb4ea98a8dbb4532272cc1e0a',
+  'catapult_revision': '665b8b46209c1de8a1878c40b5cbb29d3e06c922',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libFuzzer
   # and whatever else without interference from each other.
diff --git a/WATCHLISTS b/WATCHLISTS
index f8fcfb37b..31907fc 100644
--- a/WATCHLISTS
+++ b/WATCHLISTS
@@ -1502,6 +1502,9 @@
     'usb': {
       'filepath': '/usb/',
     },
+    'vaapi': {
+      'filepath': 'media/gpu/vaapi',
+    },
     'valgrind': {
       'filepath': 'valgrind',
     },
@@ -2278,6 +2281,7 @@
     'usb': ['cco3+watch@chromium.org',
             'mattreynolds+watch@chromium.org',
             'scheib+watch@chromium.org'],
+    'vaapi': ['vaapi-reviews@chromium.org'],
     'valgrind': ['bruening+watch@chromium.org',
                  'glider+watch@chromium.org'],
     'version_assembly': ['caitkp+watch@chromium.org',
diff --git a/chrome/VERSION b/chrome/VERSION
index 8de2bdb..03f1f8f 100644
--- a/chrome/VERSION
+++ b/chrome/VERSION
@@ -1,4 +1,4 @@
 MAJOR=65
 MINOR=0
-BUILD=3291
+BUILD=3292
 PATCH=0
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/firstrun/FirstRunFlowSequencer.java b/chrome/android/java/src/org/chromium/chrome/browser/firstrun/FirstRunFlowSequencer.java
index 9bfda91b..de6a0f8e 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/firstrun/FirstRunFlowSequencer.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/firstrun/FirstRunFlowSequencer.java
@@ -29,6 +29,7 @@
 import org.chromium.chrome.browser.util.FeatureUtilities;
 import org.chromium.chrome.browser.util.IntentUtils;
 import org.chromium.chrome.browser.vr_shell.VrIntentUtils;
+import org.chromium.chrome.browser.webapps.WebApkActivity;
 import org.chromium.components.signin.AccountManagerFacade;
 import org.chromium.components.signin.ChromeSigninController;
 
@@ -276,10 +277,16 @@
         return intent;
     }
 
-    /** Returns an intent to show lightweight first run activity. */
-    public static Intent createLightweightFirstRunIntent(Context context) {
+    /**
+     * Returns an intent to show the lightweight first run activity.
+     * @param context        The context.
+     * @param fromIntent     The intent that was used to launch Chrome.
+     */
+    private static Intent createLightweightFirstRunIntent(Context context, Intent fromIntent) {
         Intent intent = new Intent();
         intent.setClassName(context, LightweightFirstRunActivity.class.getName());
+        String appName = WebApkActivity.slowExtractNameFromIntentIfTargetIsWebApk(fromIntent);
+        intent.putExtra(LightweightFirstRunActivity.EXTRA_ASSOCIATED_APP_NAME, appName);
         return intent;
     }
 
@@ -354,7 +361,7 @@
             // Launch the Generic First Run Experience if it was previously active.
             Intent freIntent = null;
             if (preferLightweightFre && !isGenericFreActive) {
-                freIntent = createLightweightFirstRunIntent(caller);
+                freIntent = createLightweightFirstRunIntent(caller, intent);
             } else {
                 freIntent = createGenericFirstRunIntent(
                         caller, TextUtils.equals(intent.getAction(), Intent.ACTION_MAIN));
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/firstrun/LightweightFirstRunActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/firstrun/LightweightFirstRunActivity.java
index 8c029ea..c3151b3 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/firstrun/LightweightFirstRunActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/firstrun/LightweightFirstRunActivity.java
@@ -15,6 +15,7 @@
 
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.customtabs.CustomTabActivity;
+import org.chromium.chrome.browser.util.IntentUtils;
 import org.chromium.ui.base.LocalizationUtils;
 import org.chromium.ui.text.NoUnderlineClickableSpan;
 import org.chromium.ui.text.SpanApplier;
@@ -29,6 +30,9 @@
     private boolean mNativeInitialized;
     private boolean mTriggerAcceptAfterNativeInit;
 
+    public static final String EXTRA_ASSOCIATED_APP_NAME =
+            "org.chromium.chrome.browser.firstrun.AssociatedAppName";
+
     @Override
     public void setContentView() {
         setFinishOnTouchOutside(true);
@@ -71,18 +75,25 @@
                 showInfoPage(R.string.family_link_privacy_policy_url);
             }
         };
+        String associatedAppName =
+                IntentUtils.safeGetStringExtra(getIntent(), EXTRA_ASSOCIATED_APP_NAME);
+        if (associatedAppName == null) {
+            associatedAppName = "";
+        }
         final CharSequence tosAndPrivacyText;
         if (hasChildAccount) {
             tosAndPrivacyText = SpanApplier.applySpans(
-                    getString(R.string.lightweight_fre_tos_and_privacy_child_account),
+                    getString(R.string.lightweight_fre_associated_app_tos_and_privacy_child_account,
+                            associatedAppName),
                     new SpanInfo("<LINK1>", "</LINK1>", clickableTermsSpan),
                     new SpanInfo("<LINK2>", "</LINK2>", clickablePrivacySpan),
                     new SpanInfo("<LINK3>", "</LINK3>", clickableFamilyLinkPrivacySpan));
         } else {
-            tosAndPrivacyText =
-                    SpanApplier.applySpans(getString(R.string.lightweight_fre_tos_and_privacy),
-                            new SpanInfo("<LINK1>", "</LINK1>", clickableTermsSpan),
-                            new SpanInfo("<LINK2>", "</LINK2>", clickablePrivacySpan));
+            tosAndPrivacyText = SpanApplier.applySpans(
+                    getString(R.string.lightweight_fre_associated_app_tos_and_privacy,
+                            associatedAppName),
+                    new SpanInfo("<LINK1>", "</LINK1>", clickableTermsSpan),
+                    new SpanInfo("<LINK2>", "</LINK2>", clickablePrivacySpan));
         }
         TextView tosAndPrivacyTextView =
                 (TextView) findViewById(R.id.lightweight_fre_tos_and_privacy);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkActivity.java
index 6f15777..50aadb9 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkActivity.java
@@ -38,6 +38,20 @@
 
     private static final String TAG = "cr_WebApkActivity";
 
+    /**
+     * Tries extracting the WebAPK short name from the passed in intent. Returns null if the intent
+     * does not launch a WebApkActivity. This method is slow. It makes several PackageManager calls.
+     */
+    public static String slowExtractNameFromIntentIfTargetIsWebApk(Intent intent) {
+        // Check for intents targetted at WebApkActivity and WebApkActivity0-9.
+        if (!intent.getComponent().getClassName().startsWith(WebApkActivity.class.getName())) {
+            return null;
+        }
+
+        WebApkInfo info = WebApkInfo.create(intent);
+        return (info != null) ? info.shortName() : null;
+    }
+
     @Override
     protected boolean isVerified() {
         return true;
diff --git a/chrome/android/java/strings/android_chrome_strings.grd b/chrome/android/java/strings/android_chrome_strings.grd
index a81975d..9a8f09e0 100644
--- a/chrome/android/java/strings/android_chrome_strings.grd
+++ b/chrome/android/java/strings/android_chrome_strings.grd
@@ -2224,11 +2224,11 @@
       <message name="IDS_FRE_TOS_AND_PRIVACY_CHILD_ACCOUNT" desc="Message explaining that use of Chrome is governed by Chrome's terms of service and privacy notice, and Family Link's privacy notice for children.">
         By using this application, you agree to Chrome’s <ph name="BEGIN_LINK1">&lt;LINK1&gt;</ph>Terms of Service<ph name="END_LINK1">&lt;/LINK1&gt;</ph> and <ph name="BEGIN_LINK2">&lt;LINK2&gt;</ph>Privacy Notice<ph name="END_LINK2">&lt;/LINK2&gt;</ph>, and the <ph name="BEGIN_LINK3">&lt;LINK3&gt;</ph>Privacy Notice for Google Accounts Managed with Family Link<ph name="END_LINK3">&lt;/LINK3&gt;</ph>.
       </message>
-      <message name="IDS_LIGHTWEIGHT_FRE_TOS_AND_PRIVACY" desc="Message explaining that use of Chrome is governed by Chrome's terms of service and privacy notice.">
-        By continuing, you agree to Chrome’s <ph name="BEGIN_LINK1">&lt;LINK1&gt;</ph>Terms of Service<ph name="END_LINK1">&lt;/LINK1&gt;</ph> and <ph name="BEGIN_LINK2">&lt;LINK2&gt;</ph>Privacy Notice<ph name="END_LINK2">&lt;/LINK2&gt;</ph>.
+      <message name="IDS_LIGHTWEIGHT_FRE_ASSOCIATED_APP_TOS_AND_PRIVACY" desc="Message explaining that use of Chrome is governed by Chrome's terms of service and privacy notice.">
+        <ph name="APP_NAME">%1$s<ex>Google Maps</ex></ph> will open in Chrome. By continuing, you agree to Chrome’s <ph name="BEGIN_LINK1">&lt;LINK1&gt;</ph>Terms of Service<ph name="END_LINK1">&lt;/LINK1&gt;</ph> and <ph name="BEGIN_LINK2">&lt;LINK2&gt;</ph>Privacy Notice<ph name="END_LINK2">&lt;/LINK2&gt;</ph>.
       </message>
-      <message name="IDS_LIGHTWEIGHT_FRE_TOS_AND_PRIVACY_CHILD_ACCOUNT" desc="Message explaining that use of Chrome is governed by Chrome's terms of service and privacy notice, and Family Link's privacy notice for children.">
-        By continuing, you agree to Chrome's <ph name="BEGIN_LINK1">&lt;LINK1&gt;</ph>Terms of Service<ph name="END_LINK1">&lt;/LINK1&gt;</ph> and <ph name="BEGIN_LINK2">&lt;LINK2&gt;</ph>Privacy Notice<ph name="END_LINK2">&lt;/LINK2&gt;</ph>, and the <ph name="BEGIN_LINK3">&lt;LINK3&gt;</ph>Privacy Notice for Google Accounts Managed with Family Link<ph name="END_LINK3">&lt;/LINK3&gt;</ph>.
+      <message name="IDS_LIGHTWEIGHT_FRE_ASSOCIATED_APP_TOS_AND_PRIVACY_CHILD_ACCOUNT" desc="Message explaining that use of Chrome is governed by Chrome's terms of service and privacy notice, and Family Link's privacy notice for children.">
+        <ph name="APP_NAME">%1$s<ex>Google Maps</ex></ph> will open in Chrome. By continuing, you agree to Chrome's <ph name="BEGIN_LINK1">&lt;LINK1&gt;</ph>Terms of Service<ph name="END_LINK1">&lt;/LINK1&gt;</ph> and <ph name="BEGIN_LINK2">&lt;LINK2&gt;</ph>Privacy Notice<ph name="END_LINK2">&lt;/LINK2&gt;</ph>, and the <ph name="BEGIN_LINK3">&lt;LINK3&gt;</ph>Privacy Notice for Google Accounts Managed with Family Link<ph name="END_LINK3">&lt;/LINK3&gt;</ph>.
       </message>
       <message name="IDS_FRE_SEND_REPORT_CHECK" desc="Text for asking the user to allow sending stats and crash reports">
         Help make Chrome better by sending usage statistics and crash reports to Google.
diff --git a/chrome/browser/budget_service/budget_service_impl.cc b/chrome/browser/budget_service/budget_service_impl.cc
index acadc77..f170e80 100644
--- a/chrome/browser/budget_service/budget_service_impl.cc
+++ b/chrome/browser/budget_service/budget_service_impl.cc
@@ -14,8 +14,9 @@
 #include "content/public/browser/render_process_host.h"
 #include "mojo/public/cpp/bindings/strong_binding.h"
 
-BudgetServiceImpl::BudgetServiceImpl(int render_process_id)
-    : render_process_id_(render_process_id) {}
+BudgetServiceImpl::BudgetServiceImpl(int render_process_id,
+                                     const url::Origin& origin)
+    : render_process_id_(render_process_id), origin_(origin) {}
 
 BudgetServiceImpl::~BudgetServiceImpl() = default;
 
@@ -23,8 +24,9 @@
 void BudgetServiceImpl::Create(blink::mojom::BudgetServiceRequest request,
                                content::RenderProcessHost* host,
                                const url::Origin& origin) {
-  mojo::MakeStrongBinding(base::MakeUnique<BudgetServiceImpl>(host->GetID()),
-                          std::move(request));
+  mojo::MakeStrongBinding(
+      base::MakeUnique<BudgetServiceImpl>(host->GetID(), origin),
+      std::move(request));
 }
 
 void BudgetServiceImpl::GetCost(blink::mojom::BudgetOperationType type,
@@ -42,8 +44,7 @@
   std::move(callback).Run(cost);
 }
 
-void BudgetServiceImpl::GetBudget(const url::Origin& origin,
-                                  GetBudgetCallback callback) {
+void BudgetServiceImpl::GetBudget(GetBudgetCallback callback) {
   // The RenderProcessHost should still be alive as long as any connections are
   // alive, and if the BudgetService mojo connection is down, the
   // BudgetServiceImpl should have been destroyed.
@@ -62,8 +63,8 @@
   // something the impact of which has to be reconsidered when the feature is
   // ready to ship for real. See https://crbug.com/710809 for context.
   if (permission_manager->GetPermissionStatus(
-          content::PermissionType::NOTIFICATIONS, origin.GetURL(),
-          origin.GetURL()) != blink::mojom::PermissionStatus::GRANTED) {
+          content::PermissionType::NOTIFICATIONS, origin_.GetURL(),
+          origin_.GetURL()) != blink::mojom::PermissionStatus::GRANTED) {
     blink::mojom::BudgetStatePtr empty_state(blink::mojom::BudgetState::New());
     empty_state->budget_at = 0;
     empty_state->time =
@@ -78,12 +79,11 @@
   }
 
   // Query the BudgetManager for the budget.
-  BudgetManagerFactory::GetForProfile(profile)->GetBudget(origin,
+  BudgetManagerFactory::GetForProfile(profile)->GetBudget(origin_,
                                                           std::move(callback));
 }
 
-void BudgetServiceImpl::Reserve(const url::Origin& origin,
-                                blink::mojom::BudgetOperationType operation,
+void BudgetServiceImpl::Reserve(blink::mojom::BudgetOperationType operation,
                                 ReserveCallback callback) {
   // The RenderProcessHost should still be alive as long as any connections are
   // alive, and if the BudgetService mojo connection is down, the
@@ -94,6 +94,6 @@
 
   // Request a reservation from the BudgetManager.
   content::BrowserContext* context = host->GetBrowserContext();
-  BudgetManagerFactory::GetForProfile(context)->Reserve(origin, operation,
+  BudgetManagerFactory::GetForProfile(context)->Reserve(origin_, operation,
                                                         std::move(callback));
 }
diff --git a/chrome/browser/budget_service/budget_service_impl.h b/chrome/browser/budget_service/budget_service_impl.h
index 044836d..db02b38 100644
--- a/chrome/browser/budget_service/budget_service_impl.h
+++ b/chrome/browser/budget_service/budget_service_impl.h
@@ -7,21 +7,18 @@
 
 #include "base/macros.h"
 #include "third_party/WebKit/public/platform/modules/budget_service/budget_service.mojom.h"
+#include "url/origin.h"
 
 namespace content {
 class RenderProcessHost;
 }
 
-namespace url {
-class Origin;
-}
-
 // Implementation of the BudgetService Mojo service provided by the browser
 // layer. It is responsible for dispatching budget requests to the
 // BudgetManager.
 class BudgetServiceImpl : public blink::mojom::BudgetService {
  public:
-  explicit BudgetServiceImpl(int render_process_id);
+  BudgetServiceImpl(int render_process_id, const url::Origin& origin);
   ~BudgetServiceImpl() override;
 
   static void Create(blink::mojom::BudgetServiceRequest request,
@@ -31,15 +28,15 @@
   // blink::mojom::BudgetService implementation.
   void GetCost(blink::mojom::BudgetOperationType operation,
                GetCostCallback callback) override;
-  void GetBudget(const url::Origin& origin,
-                 GetBudgetCallback callback) override;
-  void Reserve(const url::Origin& origin,
-               blink::mojom::BudgetOperationType operation,
+  void GetBudget(GetBudgetCallback callback) override;
+  void Reserve(blink::mojom::BudgetOperationType operation,
                ReserveCallback callback) override;
 
  private:
   // Render process ID is used to get the browser context.
-  int render_process_id_;
+  const int render_process_id_;
+
+  const url::Origin origin_;
 
   DISALLOW_COPY_AND_ASSIGN(BudgetServiceImpl);
 };
diff --git a/chrome/browser/extensions/api/input_ime/input_ime_api_chromeos.cc b/chrome/browser/extensions/api/input_ime/input_ime_api_chromeos.cc
index 32151e9..dedf48b0 100644
--- a/chrome/browser/extensions/api/input_ime/input_ime_api_chromeos.cc
+++ b/chrome/browser/extensions/api/input_ime/input_ime_api_chromeos.cc
@@ -25,6 +25,8 @@
 #include "ui/base/ime/chromeos/extension_ime_util.h"
 #include "ui/base/ime/chromeos/input_method_manager.h"
 #include "ui/base/ime/ime_engine_handler_interface.h"
+#include "ui/keyboard/keyboard_controller.h"
+#include "ui/keyboard/keyboard_util.h"
 
 namespace input_ime = extensions::api::input_ime;
 namespace DeleteSurroundingText =
@@ -627,7 +629,23 @@
   InputImeEventRouter* event_router =
       GetInputImeEventRouter(Profile::FromBrowserContext(browser_context));
   if (input_components && event_router) {
-    event_router->RegisterImeExtension(extension->id(), *input_components);
+    if (extension->id() == event_router->GetUnloadedExtensionId()) {
+      // After the 1st-party IME extension being unloaded unexpectedly,
+      // we don't unregister the IME entries so after the extension being
+      // reloaded we should reactivate the engine so that the IME extension
+      // can receive the onActivate event to recover itself upon the
+      // unexpected unload.
+      InputMethodEngineBase* engine =
+          event_router->GetActiveEngine(extension->id());
+      // When extension is unloaded unexpectedly and reloaded, OS doesn't pass
+      // details.browser_context value in OnListenerAdded callback. So we need
+      // to reactivate engine here.
+      if (engine)
+        engine->Enable(engine->GetActiveComponentId());
+      event_router->SetUnloadedExtensionId("");
+    } else {
+      event_router->RegisterImeExtension(extension->id(), *input_components);
+    }
   }
 }
 
@@ -640,7 +658,34 @@
     return;
   InputImeEventRouter* event_router =
       GetInputImeEventRouter(Profile::FromBrowserContext(browser_context));
-  if (event_router) {
+  if (!event_router)
+    return;
+  chromeos::input_method::InputMethodManager* manager =
+      chromeos::input_method::InputMethodManager::Get();
+  chromeos::ComponentExtensionIMEManager* comp_ext_ime_manager =
+      manager->GetComponentExtensionIMEManager();
+
+  if (comp_ext_ime_manager->IsWhitelistedExtension(extension->id())) {
+    // Since the first party ime is not allow to uninstall, and when it's
+    // unloaded unexpectedly, OS will recover the extension at once.
+    // So should not unregister the IMEs. Otherwise the IME icons on the
+    // desktop shelf will disappear. see bugs: 775507,788247,786273,761714.
+    // But still need to unload keyboard container document. Since ime extension
+    // need to re-render the document when it's recovered.
+    keyboard::KeyboardController* keyboard_controller =
+        keyboard::KeyboardController::GetInstance();
+    if (keyboard_controller) {
+      // Keyboard controller "Reload" method only reload current page when the
+      // url is changed. So we need unload the current page first. Then next
+      // engine->Enable() can refresh the inputview page correctly.
+      // Empties the content url and reload the controller to unload the
+      // current page.
+      // TODO(wuyingbing): Should add a new method to unload the document.
+      keyboard::SetOverrideContentUrl(GURL());
+      keyboard_controller->Reload();
+    }
+    event_router->SetUnloadedExtensionId(extension->id());
+  } else {
     event_router->UnregisterAllImes(extension->id());
   }
 }
diff --git a/chrome/browser/extensions/api/input_ime/input_ime_api_chromeos.h b/chrome/browser/extensions/api/input_ime/input_ime_api_chromeos.h
index 7960ef8e..0d434e3 100644
--- a/chrome/browser/extensions/api/input_ime/input_ime_api_chromeos.h
+++ b/chrome/browser/extensions/api/input_ime/input_ime_api_chromeos.h
@@ -148,9 +148,19 @@
   input_method::InputMethodEngineBase* GetActiveEngine(
       const std::string& extension_id) override;
 
+  std::string GetUnloadedExtensionId() const {
+    return unloaded_component_extension_id_;
+  }
+
+  void SetUnloadedExtensionId(const std::string& extension_id) {
+    unloaded_component_extension_id_ = extension_id;
+  }
+
  private:
   // The engine map from extension_id to an engine.
   std::map<std::string, chromeos::InputMethodEngine*> engine_map_;
+  // The first party ime extension which is unloaded unexpectedly.
+  std::string unloaded_component_extension_id_;
 
   DISALLOW_COPY_AND_ASSIGN(InputImeEventRouter);
 };
diff --git a/chrome/browser/page_load_metrics/observers/page_load_metrics_observer_test_harness.cc b/chrome/browser/page_load_metrics/observers/page_load_metrics_observer_test_harness.cc
index 3336756..8b31ced3 100644
--- a/chrome/browser/page_load_metrics/observers/page_load_metrics_observer_test_harness.cc
+++ b/chrome/browser/page_load_metrics/observers/page_load_metrics_observer_test_harness.cc
@@ -107,8 +107,10 @@
 void PageLoadMetricsObserverTestHarness::NavigateWithPageTransitionAndCommit(
     const GURL& url,
     ui::PageTransition transition) {
-  controller().LoadURL(url, content::Referrer(), transition, std::string());
-  content::WebContentsTester::For(web_contents())->CommitPendingNavigation();
+  auto simulator =
+      content::NavigationSimulator::CreateRendererInitiated(url, main_rfh());
+  simulator->SetTransition(transition);
+  simulator->Commit();
 }
 
 void PageLoadMetricsObserverTestHarness::NavigateToUntrackedUrl() {
diff --git a/chrome/browser/resources/chromeos/chromevox/cvox2/background/output.js b/chrome/browser/resources/chromeos/chromevox/cvox2/background/output.js
index cf4ccc6..4d47725 100644
--- a/chrome/browser/resources/chromeos/chromevox/cvox2/background/output.js
+++ b/chrome/browser/resources/chromeos/chromevox/cvox2/background/output.js
@@ -365,6 +365,9 @@
     },
     inlineTextBox: {speak: `$name=`},
     inputTime: {enter: `$nameFromNode $role $state $restriction $description`},
+    labelText: {
+      speak: `$name $value $state $restriction $description`,
+    },
     lineBreak: {speak: `$name=`},
     link: {
       enter: `$nameFromNode= $role $state $restriction`,
diff --git a/chrome/browser/ui/views/accessibility/invert_bubble_view.cc b/chrome/browser/ui/views/accessibility/invert_bubble_view.cc
index 92009a2..35421ac 100644
--- a/chrome/browser/ui/views/accessibility/invert_bubble_view.cc
+++ b/chrome/browser/ui/views/accessibility/invert_bubble_view.cc
@@ -172,8 +172,6 @@
 
 }  // namespace
 
-namespace chrome {
-
 void MaybeShowInvertBubbleView(BrowserView* browser_view) {
   Browser* browser = browser_view->browser();
   PrefService* pref_service = browser->profile()->GetPrefs();
@@ -189,5 +187,3 @@
   InvertBubbleView* delegate = new InvertBubbleView(browser, anchor);
   views::BubbleDialogDelegateView::CreateBubble(delegate)->Show();
 }
-
-}  // namespace chrome
diff --git a/chrome/browser/ui/views/accessibility/invert_bubble_view.h b/chrome/browser/ui/views/accessibility/invert_bubble_view.h
index b1736c65..86ad29c 100644
--- a/chrome/browser/ui/views/accessibility/invert_bubble_view.h
+++ b/chrome/browser/ui/views/accessibility/invert_bubble_view.h
@@ -12,8 +12,6 @@
 class View;
 }
 
-namespace chrome {
-
 // Show a bubble telling the user that they're using Windows high-contrast mode
 // with a light-on-dark scheme, so they may be interested in a high-contrast
 // Chrome extension and a dark theme. Only shows the first time we encounter
@@ -23,6 +21,4 @@
 // Shows the above bubble unconditionally.
 void ShowInvertBubbleView(Browser* browser, views::View* anchor);
 
-}  // namespace chrome
-
 #endif  // CHROME_BROWSER_UI_VIEWS_ACCESSIBILITY_INVERT_BUBBLE_VIEW_H_
diff --git a/chrome/browser/ui/views/accessibility/invert_bubble_view_browsertest.cc b/chrome/browser/ui/views/accessibility/invert_bubble_view_browsertest.cc
index c31a254..f4a01ba 100644
--- a/chrome/browser/ui/views/accessibility/invert_bubble_view_browsertest.cc
+++ b/chrome/browser/ui/views/accessibility/invert_bubble_view_browsertest.cc
@@ -16,7 +16,7 @@
 
   // DialogBrowserTest:
   void ShowDialog(const std::string& name) override {
-    chrome::ShowInvertBubbleView(browser(), &anchor_);
+    ShowInvertBubbleView(browser(), &anchor_);
   }
 
  private:
diff --git a/chrome/browser/ui/views/frame/browser_view.cc b/chrome/browser/ui/views/frame/browser_view.cc
index 143f5586..9ab8c26 100644
--- a/chrome/browser/ui/views/frame/browser_view.cc
+++ b/chrome/browser/ui/views/frame/browser_view.cc
@@ -619,7 +619,7 @@
 
   browser()->OnWindowDidShow();
 
-  chrome::MaybeShowInvertBubbleView(this);
+  MaybeShowInvertBubbleView(this);
 }
 
 void BrowserView::ShowInactive() {
@@ -1625,7 +1625,7 @@
   // Don't infinitely recurse.
   if (!handling_theme_changed_)
     UserChangedTheme();
-  chrome::MaybeShowInvertBubbleView(this);
+  MaybeShowInvertBubbleView(this);
 }
 
 FullscreenControlHost* BrowserView::GetFullscreenControlHost() {
diff --git a/chrome/renderer/extensions/automation_ax_tree_wrapper.cc b/chrome/renderer/extensions/automation_ax_tree_wrapper.cc
index 5270c2c..f71b3a0f6 100644
--- a/chrome/renderer/extensions/automation_ax_tree_wrapper.cc
+++ b/chrome/renderer/extensions/automation_ax_tree_wrapper.cc
@@ -2,21 +2,335 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "chrome/common/extensions/chrome_extension_messages.h"
 #include "chrome/renderer/extensions/automation_internal_custom_bindings.h"
+#include "ui/accessibility/ax_node.h"
 
 namespace extensions {
 
+namespace {
+
+// Convert from AXEvent to api::automation::EventType.
+api::automation::EventType ToAutomationEvent(ui::AXEvent event_type) {
+  switch (event_type) {
+    case ui::AX_EVENT_NONE:
+      return api::automation::EVENT_TYPE_NONE;
+    case ui::AX_EVENT_ACTIVEDESCENDANTCHANGED:
+      return api::automation::EVENT_TYPE_ACTIVEDESCENDANTCHANGED;
+    case ui::AX_EVENT_ALERT:
+      return api::automation::EVENT_TYPE_ALERT;
+    case ui::AX_EVENT_ARIA_ATTRIBUTE_CHANGED:
+      return api::automation::EVENT_TYPE_ARIAATTRIBUTECHANGED;
+    case ui::AX_EVENT_AUTOCORRECTION_OCCURED:
+      return api::automation::EVENT_TYPE_AUTOCORRECTIONOCCURED;
+    case ui::AX_EVENT_BLUR:
+      return api::automation::EVENT_TYPE_BLUR;
+    case ui::AX_EVENT_CHECKED_STATE_CHANGED:
+      return api::automation::EVENT_TYPE_CHECKEDSTATECHANGED;
+    case ui::AX_EVENT_CHILDREN_CHANGED:
+      return api::automation::EVENT_TYPE_CHILDRENCHANGED;
+    case ui::AX_EVENT_CLICKED:
+      return api::automation::EVENT_TYPE_CLICKED;
+    case ui::AX_EVENT_DOCUMENT_SELECTION_CHANGED:
+      return api::automation::EVENT_TYPE_DOCUMENTSELECTIONCHANGED;
+    case ui::AX_EVENT_EXPANDED_CHANGED:
+      return api::automation::EVENT_TYPE_EXPANDEDCHANGED;
+    case ui::AX_EVENT_FOCUS:
+      return api::automation::EVENT_TYPE_FOCUS;
+    case ui::AX_EVENT_HIDE:
+      return api::automation::EVENT_TYPE_HIDE;
+    case ui::AX_EVENT_HOVER:
+      return api::automation::EVENT_TYPE_HOVER;
+    case ui::AX_EVENT_IMAGE_FRAME_UPDATED:
+      return api::automation::EVENT_TYPE_IMAGEFRAMEUPDATED;
+    case ui::AX_EVENT_INVALID_STATUS_CHANGED:
+      return api::automation::EVENT_TYPE_INVALIDSTATUSCHANGED;
+    case ui::AX_EVENT_LAYOUT_COMPLETE:
+      return api::automation::EVENT_TYPE_LAYOUTCOMPLETE;
+    case ui::AX_EVENT_LIVE_REGION_CREATED:
+      return api::automation::EVENT_TYPE_LIVEREGIONCREATED;
+    case ui::AX_EVENT_LIVE_REGION_CHANGED:
+      return api::automation::EVENT_TYPE_LIVEREGIONCHANGED;
+    case ui::AX_EVENT_LOAD_COMPLETE:
+      return api::automation::EVENT_TYPE_LOADCOMPLETE;
+    case ui::AX_EVENT_LOCATION_CHANGED:
+      return api::automation::EVENT_TYPE_LOCATIONCHANGED;
+    case ui::AX_EVENT_MEDIA_STARTED_PLAYING:
+      return api::automation::EVENT_TYPE_MEDIASTARTEDPLAYING;
+    case ui::AX_EVENT_MEDIA_STOPPED_PLAYING:
+      return api::automation::EVENT_TYPE_MEDIASTOPPEDPLAYING;
+    case ui::AX_EVENT_MENU_END:
+      return api::automation::EVENT_TYPE_MENUEND;
+    case ui::AX_EVENT_MENU_LIST_ITEM_SELECTED:
+      return api::automation::EVENT_TYPE_MENULISTITEMSELECTED;
+    case ui::AX_EVENT_MENU_LIST_VALUE_CHANGED:
+      return api::automation::EVENT_TYPE_MENULISTVALUECHANGED;
+    case ui::AX_EVENT_MENU_POPUP_END:
+      return api::automation::EVENT_TYPE_MENUPOPUPEND;
+    case ui::AX_EVENT_MENU_POPUP_START:
+      return api::automation::EVENT_TYPE_MENUPOPUPSTART;
+    case ui::AX_EVENT_MENU_START:
+      return api::automation::EVENT_TYPE_MENUSTART;
+    case ui::AX_EVENT_MOUSE_CANCELED:
+      return api::automation::EVENT_TYPE_MOUSECANCELED;
+    case ui::AX_EVENT_MOUSE_DRAGGED:
+      return api::automation::EVENT_TYPE_MOUSEDRAGGED;
+    case ui::AX_EVENT_MOUSE_MOVED:
+      return api::automation::EVENT_TYPE_MOUSEMOVED;
+    case ui::AX_EVENT_MOUSE_PRESSED:
+      return api::automation::EVENT_TYPE_MOUSEPRESSED;
+    case ui::AX_EVENT_MOUSE_RELEASED:
+      return api::automation::EVENT_TYPE_MOUSERELEASED;
+    case ui::AX_EVENT_ROW_COLLAPSED:
+      return api::automation::EVENT_TYPE_ROWCOLLAPSED;
+    case ui::AX_EVENT_ROW_COUNT_CHANGED:
+      return api::automation::EVENT_TYPE_ROWCOUNTCHANGED;
+    case ui::AX_EVENT_ROW_EXPANDED:
+      return api::automation::EVENT_TYPE_ROWEXPANDED;
+    case ui::AX_EVENT_SCROLL_POSITION_CHANGED:
+      return api::automation::EVENT_TYPE_SCROLLPOSITIONCHANGED;
+    case ui::AX_EVENT_SCROLLED_TO_ANCHOR:
+      return api::automation::EVENT_TYPE_SCROLLEDTOANCHOR;
+    case ui::AX_EVENT_SELECTED_CHILDREN_CHANGED:
+      return api::automation::EVENT_TYPE_SELECTEDCHILDRENCHANGED;
+    case ui::AX_EVENT_SELECTION:
+      return api::automation::EVENT_TYPE_SELECTION;
+    case ui::AX_EVENT_SELECTION_ADD:
+      return api::automation::EVENT_TYPE_SELECTIONADD;
+    case ui::AX_EVENT_SELECTION_REMOVE:
+      return api::automation::EVENT_TYPE_SELECTIONREMOVE;
+    case ui::AX_EVENT_SHOW:
+      return api::automation::EVENT_TYPE_SHOW;
+    case ui::AX_EVENT_TEXT_CHANGED:
+      return api::automation::EVENT_TYPE_TEXTCHANGED;
+    case ui::AX_EVENT_TEXT_SELECTION_CHANGED:
+      return api::automation::EVENT_TYPE_TEXTSELECTIONCHANGED;
+    case ui::AX_EVENT_TREE_CHANGED:
+      return api::automation::EVENT_TYPE_TREECHANGED;
+    case ui::AX_EVENT_VALUE_CHANGED:
+      return api::automation::EVENT_TYPE_VALUECHANGED;
+  }
+
+  NOTREACHED();
+  return api::automation::EVENT_TYPE_NONE;
+}
+
+// Convert from ui::AXEventGenerator::Event to api::automation::EventType.
+api::automation::EventType ToAutomationEvent(
+    ui::AXEventGenerator::Event event_type) {
+  switch (event_type) {
+    case ui::AXEventGenerator::Event::ACTIVE_DESCENDANT_CHANGED:
+      return api::automation::EVENT_TYPE_ACTIVEDESCENDANTCHANGED;
+    case ui::AXEventGenerator::Event::ALERT:
+      return api::automation::EVENT_TYPE_ALERT;
+    case ui::AXEventGenerator::Event::CHECKED_STATE_CHANGED:
+      return api::automation::EVENT_TYPE_CHECKEDSTATECHANGED;
+    case ui::AXEventGenerator::Event::CHILDREN_CHANGED:
+      return api::automation::EVENT_TYPE_CHILDRENCHANGED;
+    case ui::AXEventGenerator::Event::DOCUMENT_SELECTION_CHANGED:
+      return api::automation::EVENT_TYPE_DOCUMENTSELECTIONCHANGED;
+    case ui::AXEventGenerator::Event::INVALID_STATUS_CHANGED:
+      return api::automation::EVENT_TYPE_INVALIDSTATUSCHANGED;
+    case ui::AXEventGenerator::Event::LIVE_REGION_CHANGED:
+      return api::automation::EVENT_TYPE_LIVEREGIONCHANGED;
+    case ui::AXEventGenerator::Event::LIVE_REGION_CREATED:
+      return api::automation::EVENT_TYPE_LIVEREGIONCREATED;
+    case ui::AXEventGenerator::Event::LOAD_COMPLETE:
+      return api::automation::EVENT_TYPE_LOADCOMPLETE;
+    case ui::AXEventGenerator::Event::MENU_ITEM_SELECTED:
+      return api::automation::EVENT_TYPE_MENULISTITEMSELECTED;
+    case ui::AXEventGenerator::Event::ROW_COUNT_CHANGED:
+      return api::automation::EVENT_TYPE_ROWCOUNTCHANGED;
+    case ui::AXEventGenerator::Event::SCROLL_POSITION_CHANGED:
+      return api::automation::EVENT_TYPE_SCROLLPOSITIONCHANGED;
+    case ui::AXEventGenerator::Event::SELECTED_CHILDREN_CHANGED:
+      return api::automation::EVENT_TYPE_SELECTEDCHILDRENCHANGED;
+    case ui::AXEventGenerator::Event::VALUE_CHANGED:
+      return api::automation::EVENT_TYPE_VALUECHANGED;
+
+    // These don't have a mapping.
+    case ui::AXEventGenerator::Event::COLLAPSED:
+    case ui::AXEventGenerator::Event::DESCRIPTION_CHANGED:
+    case ui::AXEventGenerator::Event::DOCUMENT_TITLE_CHANGED:
+    case ui::AXEventGenerator::Event::EXPANDED:
+    case ui::AXEventGenerator::Event::LIVE_REGION_NODE_CHANGED:
+    case ui::AXEventGenerator::Event::NAME_CHANGED:
+    case ui::AXEventGenerator::Event::OTHER_ATTRIBUTE_CHANGED:
+    case ui::AXEventGenerator::Event::ROLE_CHANGED:
+    case ui::AXEventGenerator::Event::SELECTED_CHANGED:
+    case ui::AXEventGenerator::Event::STATE_CHANGED:
+      return api::automation::EVENT_TYPE_NONE;
+  }
+
+  NOTREACHED();
+  return api::automation::EVENT_TYPE_NONE;
+}
+
+}  // namespace
+
 AutomationAXTreeWrapper::AutomationAXTreeWrapper(
     int32_t tree_id,
     AutomationInternalCustomBindings* owner)
     : tree_id_(tree_id), host_node_id_(-1), owner_(owner) {
-  tree_.SetDelegate(owner);
+  // We have to initialize AXEventGenerator here - we can't do it in the
+  // initializer list because AXTree hasn't been initialized yet at that point.
+  SetTree(&tree_);
 }
 
 AutomationAXTreeWrapper::~AutomationAXTreeWrapper() {
-  // Explicitly clear the delegate so that we don't get any more
-  // callbacks as the tree is destroyed.
+  // Clearing the delegate so we don't get a callback for every node
+  // being deleted.
   tree_.SetDelegate(nullptr);
 }
 
+bool AutomationAXTreeWrapper::OnAccessibilityEvent(
+    const ExtensionMsg_AccessibilityEventParams& params,
+    bool is_active_profile) {
+  deleted_node_ids_.clear();
+
+  if (!tree_.Unserialize(params.update))
+    return false;
+
+  // Don't send any events if it's not the active profile.
+  if (!is_active_profile)
+    return true;
+
+  owner_->SendNodesRemovedEvent(&tree_, deleted_node_ids_);
+  deleted_node_ids_.clear();
+
+  api::automation::EventType automation_event_type =
+      ToAutomationEvent(params.event_type);
+
+  // Send some events directly from the event message, if they're not
+  // handled by AXEventGenerator yet.
+  if (!IsEventTypeHandledByAXEventGenerator(automation_event_type)) {
+    owner_->SendAutomationEvent(params, params.id, automation_event_type);
+  }
+
+  // Send auto-generated AXEventGenerator events.
+  for (auto targeted_event : *this) {
+    api::automation::EventType event_type =
+        ToAutomationEvent(targeted_event.event);
+    if (IsEventTypeHandledByAXEventGenerator(event_type)) {
+      owner_->SendAutomationEvent(params, targeted_event.node->id(),
+                                  event_type);
+    }
+  }
+  ClearEvents();
+
+  return true;
+}
+
+void AutomationAXTreeWrapper::OnNodeDataWillChange(
+    ui::AXTree* tree,
+    const ui::AXNodeData& old_node_data,
+    const ui::AXNodeData& new_node_data) {
+  AXEventGenerator::OnNodeDataWillChange(tree, old_node_data, new_node_data);
+  if (old_node_data.GetStringAttribute(ui::AX_ATTR_NAME) !=
+      new_node_data.GetStringAttribute(ui::AX_ATTR_NAME))
+    text_changed_node_ids_.push_back(new_node_data.id);
+}
+
+void AutomationAXTreeWrapper::OnNodeWillBeDeleted(ui::AXTree* tree,
+                                                  ui::AXNode* node) {
+  AXEventGenerator::OnNodeWillBeDeleted(tree, node);
+  owner_->SendTreeChangeEvent(api::automation::TREE_CHANGE_TYPE_NODEREMOVED,
+                              tree, node);
+  deleted_node_ids_.push_back(node->id());
+}
+
+void AutomationAXTreeWrapper::OnAtomicUpdateFinished(
+    ui::AXTree* tree,
+    bool root_changed,
+    const std::vector<ui::AXTreeDelegate::Change>& changes) {
+  AXEventGenerator::OnAtomicUpdateFinished(tree, root_changed, changes);
+  DCHECK_EQ(&tree_, tree);
+  for (const auto change : changes) {
+    ui::AXNode* node = change.node;
+    switch (change.type) {
+      case NODE_CREATED:
+        owner_->SendTreeChangeEvent(
+            api::automation::TREE_CHANGE_TYPE_NODECREATED, tree, node);
+        break;
+      case SUBTREE_CREATED:
+        owner_->SendTreeChangeEvent(
+            api::automation::TREE_CHANGE_TYPE_SUBTREECREATED, tree, node);
+        break;
+      case NODE_CHANGED:
+        owner_->SendTreeChangeEvent(
+            api::automation::TREE_CHANGE_TYPE_NODECHANGED, tree, node);
+        break;
+      // Unhandled.
+      case NODE_REPARENTED:
+      case SUBTREE_REPARENTED:
+        break;
+    }
+  }
+
+  for (int id : text_changed_node_ids_) {
+    owner_->SendTreeChangeEvent(api::automation::TREE_CHANGE_TYPE_TEXTCHANGED,
+                                tree, tree->GetFromId(id));
+  }
+  text_changed_node_ids_.clear();
+}
+
+bool AutomationAXTreeWrapper::IsEventTypeHandledByAXEventGenerator(
+    api::automation::EventType event_type) const {
+  switch (event_type) {
+    case api::automation::EVENT_TYPE_LOADCOMPLETE:
+      return true;
+    case api::automation::EVENT_TYPE_NONE:
+    case api::automation::EVENT_TYPE_ACTIVEDESCENDANTCHANGED:
+    case api::automation::EVENT_TYPE_ALERT:
+    case api::automation::EVENT_TYPE_ARIAATTRIBUTECHANGED:
+    case api::automation::EVENT_TYPE_AUTOCORRECTIONOCCURED:
+    case api::automation::EVENT_TYPE_BLUR:
+    case api::automation::EVENT_TYPE_CHECKEDSTATECHANGED:
+    case api::automation::EVENT_TYPE_CHILDRENCHANGED:
+    case api::automation::EVENT_TYPE_CLICKED:
+    case api::automation::EVENT_TYPE_DOCUMENTSELECTIONCHANGED:
+    case api::automation::EVENT_TYPE_EXPANDEDCHANGED:
+    case api::automation::EVENT_TYPE_FOCUS:
+    case api::automation::EVENT_TYPE_HIDE:
+    case api::automation::EVENT_TYPE_HOVER:
+    case api::automation::EVENT_TYPE_IMAGEFRAMEUPDATED:
+    case api::automation::EVENT_TYPE_INVALIDSTATUSCHANGED:
+    case api::automation::EVENT_TYPE_LAYOUTCOMPLETE:
+    case api::automation::EVENT_TYPE_LIVEREGIONCREATED:
+    case api::automation::EVENT_TYPE_LIVEREGIONCHANGED:
+    case api::automation::EVENT_TYPE_LOCATIONCHANGED:
+    case api::automation::EVENT_TYPE_MEDIASTARTEDPLAYING:
+    case api::automation::EVENT_TYPE_MEDIASTOPPEDPLAYING:
+    case api::automation::EVENT_TYPE_MENUEND:
+    case api::automation::EVENT_TYPE_MENULISTITEMSELECTED:
+    case api::automation::EVENT_TYPE_MENULISTVALUECHANGED:
+    case api::automation::EVENT_TYPE_MENUPOPUPEND:
+    case api::automation::EVENT_TYPE_MENUPOPUPSTART:
+    case api::automation::EVENT_TYPE_MENUSTART:
+    case api::automation::EVENT_TYPE_MOUSECANCELED:
+    case api::automation::EVENT_TYPE_MOUSEDRAGGED:
+    case api::automation::EVENT_TYPE_MOUSEMOVED:
+    case api::automation::EVENT_TYPE_MOUSEPRESSED:
+    case api::automation::EVENT_TYPE_MOUSERELEASED:
+    case api::automation::EVENT_TYPE_ROWCOLLAPSED:
+    case api::automation::EVENT_TYPE_ROWCOUNTCHANGED:
+    case api::automation::EVENT_TYPE_ROWEXPANDED:
+    case api::automation::EVENT_TYPE_SCROLLPOSITIONCHANGED:
+    case api::automation::EVENT_TYPE_SCROLLEDTOANCHOR:
+    case api::automation::EVENT_TYPE_SELECTEDCHILDRENCHANGED:
+    case api::automation::EVENT_TYPE_SELECTION:
+    case api::automation::EVENT_TYPE_SELECTIONADD:
+    case api::automation::EVENT_TYPE_SELECTIONREMOVE:
+    case api::automation::EVENT_TYPE_SHOW:
+    case api::automation::EVENT_TYPE_TEXTCHANGED:
+    case api::automation::EVENT_TYPE_TEXTSELECTIONCHANGED:
+    case api::automation::EVENT_TYPE_TREECHANGED:
+    case api::automation::EVENT_TYPE_VALUECHANGED:
+      return false;
+  }
+
+  NOTREACHED();
+  return false;
+}
+
 }  // namespace extensions
diff --git a/chrome/renderer/extensions/automation_ax_tree_wrapper.h b/chrome/renderer/extensions/automation_ax_tree_wrapper.h
index e79d615..e25f548 100644
--- a/chrome/renderer/extensions/automation_ax_tree_wrapper.h
+++ b/chrome/renderer/extensions/automation_ax_tree_wrapper.h
@@ -5,18 +5,21 @@
 #ifndef CHROME_RENDERER_EXTENSIONS_AUTOMATION_AX_TREE_WRAPPER_H_
 #define CHROME_RENDERER_EXTENSIONS_AUTOMATION_AX_TREE_WRAPPER_H_
 
+#include "ui/accessibility/ax_event_generator.h"
 #include "ui/accessibility/ax_tree.h"
 
+struct ExtensionMsg_AccessibilityEventParams;
+
 namespace extensions {
 
 class AutomationInternalCustomBindings;
 
 // A class that wraps one AXTree and all of the additional state
 // and helper methods needed to use it for the automation API.
-class AutomationAXTreeWrapper {
+class AutomationAXTreeWrapper : public ui::AXEventGenerator {
  public:
   AutomationAXTreeWrapper(int tree_id, AutomationInternalCustomBindings* owner);
-  ~AutomationAXTreeWrapper();
+  ~AutomationAXTreeWrapper() override;
 
   int32_t tree_id() const { return tree_id_; }
   ui::AXTree* tree() { return &tree_; }
@@ -28,11 +31,34 @@
   int32_t host_node_id() const { return host_node_id_; }
   void set_host_node_id(int32_t id) { host_node_id_ = id; }
 
+  // Called by AutomationInternalCustomBindings::OnAccessibilityEvent on
+  // the AutomationAXTreeWrapper instance for the correct tree corresponding
+  // to this event. Unserializes the tree update and calls back to
+  // AutomationInternalCustomBindings to fire any automation events needed.
+  bool OnAccessibilityEvent(const ExtensionMsg_AccessibilityEventParams& params,
+                            bool is_active_profile);
+
  private:
+  // AXEventGenerator overrides.
+  void OnNodeDataWillChange(ui::AXTree* tree,
+                            const ui::AXNodeData& old_node_data,
+                            const ui::AXNodeData& new_node_data) override;
+  void OnNodeWillBeDeleted(ui::AXTree* tree, ui::AXNode* node) override;
+  void OnAtomicUpdateFinished(ui::AXTree* tree,
+                              bool root_changed,
+                              const std::vector<Change>& changes) override;
+
+  // Given an event, return true if the event is handled by
+  // AXEventGenerator, and false if it's not. Temporary, this will be
+  // removed with the AXEventGenerator refactoring is complete.
+  bool IsEventTypeHandledByAXEventGenerator(api::automation::EventType) const;
+
   int32_t tree_id_;
   int32_t host_node_id_;
   ui::AXTree tree_;
   AutomationInternalCustomBindings* owner_;
+  std::vector<int> deleted_node_ids_;
+  std::vector<int> text_changed_node_ids_;
 
   DISALLOW_COPY_AND_ASSIGN(AutomationAXTreeWrapper);
 };
diff --git a/chrome/renderer/extensions/automation_internal_custom_bindings.cc b/chrome/renderer/extensions/automation_internal_custom_bindings.cc
index c8d17a8..cf85247 100644
--- a/chrome/renderer/extensions/automation_internal_custom_bindings.cc
+++ b/chrome/renderer/extensions/automation_internal_custom_bindings.cc
@@ -796,10 +796,6 @@
   if (message_filter_)
     message_filter_->Detach();
 
-  // Delete the tree wrappers quickly by first clearing their delegates so
-  // we don't get a callback for every node being deleted.
-  for (auto& iter : tree_id_to_tree_wrapper_map_)
-    iter.second->tree()->SetDelegate(nullptr);
   tree_id_to_tree_wrapper_map_.clear();
 }
 
@@ -1209,9 +1205,7 @@
     tree_wrapper = iter->second.get();
   }
 
-  // Update the internal state whether it's the active profile or not.
-  deleted_node_ids_.clear();
-  if (!tree_wrapper->tree()->Unserialize(params.update)) {
+  if (!tree_wrapper->OnAccessibilityEvent(params, is_active_profile)) {
     LOG(ERROR) << tree_wrapper->tree()->error();
     base::ListValue args;
     args.AppendInteger(tree_id);
@@ -1220,27 +1214,6 @@
         nullptr, context());
     return;
   }
-
-  // Don't send any events if it's not the active profile.
-  if (!is_active_profile)
-    return;
-
-  SendNodesRemovedEvent(tree_wrapper->tree(), deleted_node_ids_);
-  deleted_node_ids_.clear();
-
-  {
-    auto event_params = base::MakeUnique<base::DictionaryValue>();
-    event_params->SetInteger("treeID", params.tree_id);
-    event_params->SetInteger("targetID", params.id);
-    event_params->SetString("eventType", ToString(params.event_type));
-    event_params->SetString("eventFrom", ToString(params.event_from));
-    event_params->SetInteger("mouseX", params.mouse_location.x());
-    event_params->SetInteger("mouseY", params.mouse_location.y());
-    base::ListValue args;
-    args.Append(std::move(event_params));
-    bindings_system_->DispatchEventInContext(
-        "automationInternal.onAccessibilityEvent", &args, nullptr, context());
-  }
 }
 
 void AutomationInternalCustomBindings::OnAccessibilityLocationChange(
@@ -1258,109 +1231,6 @@
                     params.new_location.transform.get());
 }
 
-void AutomationInternalCustomBindings::OnNodeDataWillChange(
-    ui::AXTree* tree,
-    const ui::AXNodeData& old_node_data,
-    const ui::AXNodeData& new_node_data) {
-  if (old_node_data.GetStringAttribute(ui::AX_ATTR_NAME) !=
-      new_node_data.GetStringAttribute(ui::AX_ATTR_NAME))
-    text_changed_node_ids_.push_back(new_node_data.id);
-}
-
-void AutomationInternalCustomBindings::OnTreeDataChanged(
-    ui::AXTree* tree,
-    const ui::AXTreeData& old_tree_data,
-    const ui::AXTreeData& new_tree_data) {}
-
-void AutomationInternalCustomBindings::OnNodeWillBeDeleted(ui::AXTree* tree,
-                                                           ui::AXNode* node) {
-  SendTreeChangeEvent(
-      api::automation::TREE_CHANGE_TYPE_NODEREMOVED,
-      tree, node);
-  deleted_node_ids_.push_back(node->id());
-}
-
-void AutomationInternalCustomBindings::OnSubtreeWillBeDeleted(
-    ui::AXTree* tree,
-    ui::AXNode* node) {
-  // This isn't strictly needed, as OnNodeWillBeDeleted will already be
-  // called. We could send a JS event for this only if it turns out to
-  // be needed for something.
-}
-
-void AutomationInternalCustomBindings::OnNodeWillBeReparented(
-    ui::AXTree* tree,
-    ui::AXNode* node) {
-  // Don't do anything here since the node will soon go away and be re-created.
-}
-
-void AutomationInternalCustomBindings::OnSubtreeWillBeReparented(
-    ui::AXTree* tree,
-    ui::AXNode* node) {
-  // Don't do anything here since the node will soon go away and be re-created.
-}
-
-void AutomationInternalCustomBindings::OnNodeCreated(ui::AXTree* tree,
-                                                     ui::AXNode* node) {
-  // Not needed, this is called in the middle of an update so it's not
-  // safe to trigger JS from here. Wait for the notification in
-  // OnAtomicUpdateFinished instead.
-}
-
-void AutomationInternalCustomBindings::OnNodeReparented(ui::AXTree* tree,
-                                                        ui::AXNode* node) {
-  // Not needed, this is called in the middle of an update so it's not
-  // safe to trigger JS from here. Wait for the notification in
-  // OnAtomicUpdateFinished instead.
-}
-
-void AutomationInternalCustomBindings::OnNodeChanged(ui::AXTree* tree,
-                                                     ui::AXNode* node) {
-  // Not needed, this is called in the middle of an update so it's not
-  // safe to trigger JS from here. Wait for the notification in
-  // OnAtomicUpdateFinished instead.
-}
-
-void AutomationInternalCustomBindings::OnAtomicUpdateFinished(
-    ui::AXTree* tree,
-    bool root_changed,
-    const std::vector<ui::AXTreeDelegate::Change>& changes) {
-  auto iter = axtree_to_tree_wrapper_map_.find(tree);
-  if (iter == axtree_to_tree_wrapper_map_.end())
-    return;
-
-  for (const auto change : changes) {
-    ui::AXNode* node = change.node;
-    switch (change.type) {
-      case NODE_CREATED:
-        SendTreeChangeEvent(
-            api::automation::TREE_CHANGE_TYPE_NODECREATED,
-            tree, node);
-        break;
-      case SUBTREE_CREATED:
-        SendTreeChangeEvent(
-            api::automation::TREE_CHANGE_TYPE_SUBTREECREATED,
-            tree, node);
-        break;
-      case NODE_CHANGED:
-        SendTreeChangeEvent(
-            api::automation::TREE_CHANGE_TYPE_NODECHANGED,
-            tree, node);
-        break;
-      // Unhandled.
-      case NODE_REPARENTED:
-      case SUBTREE_REPARENTED:
-        break;
-    }
-  }
-
-  for (int id : text_changed_node_ids_) {
-    SendTreeChangeEvent(api::automation::TREE_CHANGE_TYPE_TEXTCHANGED, tree,
-                        tree->GetFromId(id));
-  }
-  text_changed_node_ids_.clear();
-}
-
 void AutomationInternalCustomBindings::SendTreeChangeEvent(
     api::automation::TreeChangeType change_type,
     ui::AXTree* tree,
@@ -1433,6 +1303,23 @@
   }
 }
 
+void AutomationInternalCustomBindings::SendAutomationEvent(
+    const ExtensionMsg_AccessibilityEventParams& params,
+    int target_id,
+    api::automation::EventType event_type) {
+  auto event_params = base::MakeUnique<base::DictionaryValue>();
+  event_params->SetInteger("treeID", params.tree_id);
+  event_params->SetInteger("targetID", target_id);
+  event_params->SetString("eventType", api::automation::ToString(event_type));
+  event_params->SetString("eventFrom", ToString(params.event_from));
+  event_params->SetInteger("mouseX", params.mouse_location.x());
+  event_params->SetInteger("mouseY", params.mouse_location.y());
+  base::ListValue args;
+  args.Append(std::move(event_params));
+  bindings_system_->DispatchEventInContext(
+      "automationInternal.onAccessibilityEvent", &args, nullptr, context());
+}
+
 void AutomationInternalCustomBindings::SendChildTreeIDEvent(ui::AXTree* tree,
                                                             ui::AXNode* node) {
   auto iter = axtree_to_tree_wrapper_map_.find(tree);
diff --git a/chrome/renderer/extensions/automation_internal_custom_bindings.h b/chrome/renderer/extensions/automation_internal_custom_bindings.h
index 15719bbc..89baca58 100644
--- a/chrome/renderer/extensions/automation_internal_custom_bindings.h
+++ b/chrome/renderer/extensions/automation_internal_custom_bindings.h
@@ -33,8 +33,7 @@
 
 // The native component of custom bindings for the chrome.automationInternal
 // API.
-class AutomationInternalCustomBindings : public ObjectBackedNativeHandler,
-                                         public ui::AXTreeDelegate {
+class AutomationInternalCustomBindings : public ObjectBackedNativeHandler {
  public:
   AutomationInternalCustomBindings(ScriptContext* context,
                                    ExtensionBindingsSystem* bindings_system);
@@ -58,6 +57,14 @@
 
   float GetDeviceScaleFactor() const;
 
+  void SendNodesRemovedEvent(ui::AXTree* tree, const std::vector<int>& ids);
+  void SendTreeChangeEvent(api::automation::TreeChangeType change_type,
+                           ui::AXTree* tree,
+                           ui::AXNode* node);
+  void SendAutomationEvent(const ExtensionMsg_AccessibilityEventParams& params,
+                           int target_id,
+                           api::automation::EventType event_type);
+
  private:
   // ObjectBackedNativeHandler overrides:
   void Invalidate() override;
@@ -152,28 +159,7 @@
 
   void UpdateOverallTreeChangeObserverFilter();
 
-  // AXTreeDelegate implementation.
-  void OnNodeDataWillChange(ui::AXTree* tree,
-                            const ui::AXNodeData& old_node_data,
-                            const ui::AXNodeData& new_node_data) override;
-  void OnTreeDataChanged(ui::AXTree* tree,
-                         const ui::AXTreeData& old_tree_data,
-                         const ui::AXTreeData& new_tree_data) override;
-  void OnNodeWillBeDeleted(ui::AXTree* tree, ui::AXNode* node) override;
-  void OnSubtreeWillBeDeleted(ui::AXTree* tree, ui::AXNode* node) override;
-  void OnNodeWillBeReparented(ui::AXTree* tree, ui::AXNode* node) override;
-  void OnSubtreeWillBeReparented(ui::AXTree* tree, ui::AXNode* node) override;
-  void OnNodeCreated(ui::AXTree* tree, ui::AXNode* node) override;
-  void OnNodeReparented(ui::AXTree* tree, ui::AXNode* node) override;
-  void OnNodeChanged(ui::AXTree* tree, ui::AXNode* node) override;
-  void OnAtomicUpdateFinished(ui::AXTree* tree,
-                              bool root_changed,
-                              const std::vector<Change>& changes) override;
-  void SendTreeChangeEvent(api::automation::TreeChangeType change_type,
-                           ui::AXTree* tree,
-                           ui::AXNode* node);
   void SendChildTreeIDEvent(ui::AXTree* tree, ui::AXNode* node);
-  void SendNodesRemovedEvent(ui::AXTree* tree, const std::vector<int>& ids);
 
   std::map<int, std::unique_ptr<AutomationAXTreeWrapper>>
       tree_id_to_tree_wrapper_map_;
@@ -183,8 +169,6 @@
   std::vector<TreeChangeObserver> tree_change_observers_;
   // A bit-map of api::automation::TreeChangeObserverFilter.
   int tree_change_observer_overall_filter_;
-  std::vector<int> deleted_node_ids_;
-  std::vector<int> text_changed_node_ids_;
   ExtensionBindingsSystem* bindings_system_;
   bool should_ignore_context_;
 
diff --git a/chrome/test/chromedriver/test/run_java_tests.py b/chrome/test/chromedriver/test/run_java_tests.py
index acfe35c..c547e127 100755
--- a/chrome/test/chromedriver/test/run_java_tests.py
+++ b/chrome/test/chromedriver/test/run_java_tests.py
@@ -101,7 +101,7 @@
   sys_props = ['selenium.browser=chrome',
                'webdriver.chrome.driver=' + os.path.abspath(chromedriver_path)]
   if chrome_path:
-    if util.IsLinux() and not util.Is64Bit():
+    if util.IsLinux() and android_package_key is None:
       # Workaround for crbug.com/611886 and
       # https://bugs.chromium.org/p/chromedriver/issues/detail?id=1695
       chrome_wrapper_path = os.path.join(test_dir, 'chrome-wrapper-no-sandbox')
diff --git a/chromecast/media/cma/backend/stream_mixer.cc b/chromecast/media/cma/backend/stream_mixer.cc
index 057a699..377f1b91 100644
--- a/chromecast/media/cma/backend/stream_mixer.cc
+++ b/chromecast/media/cma/backend/stream_mixer.cc
@@ -136,6 +136,7 @@
       check_close_timeout_(kDefaultCheckCloseTimeoutMs),
       check_close_timer_(new base::Timer(false, false)),
       filter_frame_alignment_(kDefaultFilterFrameAlignment) {
+  VLOG(1) << __func__;
   if (single_threaded_for_test_) {
     mixer_task_runner_ = base::ThreadTaskRunnerHandle::Get();
   } else {
@@ -265,12 +266,14 @@
 }
 
 StreamMixer::~StreamMixer() {
+  VLOG(1) << __func__;
   FinalizeOnMixerThread();
   mixer_thread_->Stop();
   mixer_task_runner_ = nullptr;
 }
 
 void StreamMixer::FinalizeOnMixerThread() {
+  VLOG(1) << __func__;
   RUN_ON_MIXER_THREAD(&StreamMixer::FinalizeOnMixerThread);
   Close();
 
@@ -279,6 +282,7 @@
 }
 
 void StreamMixer::FinishFinalize() {
+  VLOG(1) << __func__;
   retry_write_frames_timer_.reset();
   check_close_timer_.reset();
   inputs_.clear();
@@ -286,6 +290,7 @@
 }
 
 bool StreamMixer::Start() {
+  VLOG(1) << __func__;
   DCHECK(mixer_task_runner_->BelongsToCurrentThread());
 
   if (!output_)
@@ -322,17 +327,21 @@
 }
 
 void StreamMixer::Stop() {
+  VLOG(1) << __func__;
   for (auto* observer : loopback_observers_) {
     observer->OnLoopbackInterrupted();
   }
 
-  output_->Stop();
+  if (output_) {
+    output_->Stop();
+  }
 
   state_ = kStateUninitialized;
   output_samples_per_second_ = MixerOutputStream::kInvalidSampleRate;
 }
 
 void StreamMixer::Close() {
+  VLOG(1) << __func__;
   Stop();
 }
 
@@ -677,6 +686,7 @@
 
 void StreamMixer::AddLoopbackAudioObserver(
     CastMediaShlib::LoopbackAudioObserver* observer) {
+  VLOG(1) << __func__;
   RUN_ON_MIXER_THREAD(&StreamMixer::AddLoopbackAudioObserver, observer);
   DCHECK(observer);
   DCHECK(!base::ContainsValue(loopback_observers_, observer));
@@ -685,6 +695,7 @@
 
 void StreamMixer::RemoveLoopbackAudioObserver(
     CastMediaShlib::LoopbackAudioObserver* observer) {
+  VLOG(1) << __func__;
   RUN_ON_MIXER_THREAD(&StreamMixer::RemoveLoopbackAudioObserver, observer);
   DCHECK(base::ContainsValue(loopback_observers_, observer));
   loopback_observers_.erase(std::remove(loopback_observers_.begin(),
diff --git a/components/arc/ime/arc_ime_service.cc b/components/arc/ime/arc_ime_service.cc
index a1cb812a..51935c3 100644
--- a/components/arc/ime/arc_ime_service.cc
+++ b/components/arc/ime/arc_ime_service.cc
@@ -279,13 +279,18 @@
 
 ////////////////////////////////////////////////////////////////////////////////
 // Overridden from keyboard::KeyboardControllerObserver
-void ArcImeService::OnKeyboardBoundsChanging(const gfx::Rect& new_bounds) {
+void ArcImeService::OnKeyboardAppearanceChanging(
+    const keyboard::KeyboardStateDescriptor& state) {
   if (!focused_arc_window_)
     return;
   aura::Window* window = focused_arc_window_;
+  gfx::Rect new_bounds = state.occluded_bounds;
   // Multiply by the scale factor. To convert from DPI to physical pixels.
   gfx::Rect bounds_in_px = gfx::ScaleToEnclosingRect(
       new_bounds, window->layer()->device_scale_factor());
+
+  // TODO(b/70251261): In addition to the bounds, the state.is_available value
+  // needs to be conveyed to the ime bridge as well.
   ime_bridge_->SendOnKeyboardBoundsChanging(bounds_in_px);
 }
 
diff --git a/components/arc/ime/arc_ime_service.h b/components/arc/ime/arc_ime_service.h
index 39a81c9..d1d8bce 100644
--- a/components/arc/ime/arc_ime_service.h
+++ b/components/arc/ime/arc_ime_service.h
@@ -95,7 +95,8 @@
       const gfx::Range& selection_range) override;
 
   // Overridden from keyboard::KeyboardControllerObserver.
-  void OnKeyboardBoundsChanging(const gfx::Rect& rect) override;
+  void OnKeyboardAppearanceChanging(
+      const keyboard::KeyboardStateDescriptor& state) override;
 
   // Overridden from ui::TextInputClient:
   void SetCompositionText(const ui::CompositionText& composition) override;
diff --git a/components/ukm/ukm_recorder_impl.cc b/components/ukm/ukm_recorder_impl.cc
index 28a5bbd..8f0ba3c 100644
--- a/components/ukm/ukm_recorder_impl.cc
+++ b/components/ukm/ukm_recorder_impl.cc
@@ -202,7 +202,7 @@
 
 bool UkmRecorderImpl::ShouldRestrictToWhitelistedSourceIds() const {
   return base::GetFieldTrialParamByFeatureAsBool(
-      kUkmFeature, "RestrictToWhitelistedSourceIds", true);
+      kUkmFeature, "RestrictToWhitelistedSourceIds", false);
 }
 
 void UkmRecorderImpl::UpdateSourceURL(SourceId source_id,
diff --git a/components/url_formatter/idn_spoof_checker.cc b/components/url_formatter/idn_spoof_checker.cc
index 16ee945..a88c5e8f 100644
--- a/components/url_formatter/idn_spoof_checker.cc
+++ b/components/url_formatter/idn_spoof_checker.cc
@@ -5,6 +5,7 @@
 #include "components/url_formatter/idn_spoof_checker.h"
 
 #include "base/numerics/safe_conversions.h"
+#include "base/strings/string_piece.h"
 #include "base/strings/string_split.h"
 #include "base/strings/string_util.h"
 #include "base/threading/thread_local_storage.h"
@@ -27,6 +28,8 @@
 #include "components/url_formatter/top_domains/alexa_skeletons-inc.cc"
 // All the domains in the above file have 3 or fewer labels.
 const size_t kNumberOfLabelsToCheck = 3;
+const unsigned char* g_graph = kDafsa;
+size_t g_graph_length = sizeof(kDafsa);
 
 bool LookupMatchInTopDomains(base::StringPiece skeleton) {
   DCHECK_NE(skeleton.back(), '.');
@@ -41,7 +44,7 @@
   while (labels.size() > 1) {
     std::string partial_skeleton = base::JoinString(labels, ".");
     if (net::LookupStringInFixedSet(
-            kDafsa, arraysize(kDafsa), partial_skeleton.data(),
+            g_graph, g_graph_length, partial_skeleton.data(),
             partial_skeleton.length()) != net::kDafsaNotFound)
       return true;
     labels.erase(labels.begin());
@@ -396,4 +399,15 @@
   uspoof_setAllowedUnicodeSet(checker_, &allowed_set, status);
 }
 
+void IDNSpoofChecker::RestoreTopDomainGraphToDefault() {
+  g_graph = kDafsa;
+  g_graph_length = sizeof(kDafsa);
+}
+
+void IDNSpoofChecker::SetTopDomainGraph(base::StringPiece domain_graph) {
+  DCHECK_NE(0u, domain_graph.length());
+  g_graph = reinterpret_cast<const unsigned char*>(domain_graph.data());
+  g_graph_length = domain_graph.length();
+}
+
 }  // namespace url_formatter
diff --git a/components/url_formatter/idn_spoof_checker.h b/components/url_formatter/idn_spoof_checker.h
index 02dbab3..5778c3b 100644
--- a/components/url_formatter/idn_spoof_checker.h
+++ b/components/url_formatter/idn_spoof_checker.h
@@ -8,8 +8,9 @@
 #include <memory>
 #include <string>
 
+#include "base/gtest_prod_util.h"
 #include "base/strings/string16.h"
-#include "base/strings/string_piece.h"
+#include "base/strings/string_piece_forward.h"
 #include "third_party/icu/source/common/unicode/uniset.h"
 #include "third_party/icu/source/common/unicode/utypes.h"
 #include "third_party/icu/source/common/unicode/uversion.h"
@@ -25,6 +26,7 @@
 struct USpoofChecker;
 
 namespace url_formatter {
+FORWARD_DECLARE_TEST(UrlFormatterTest, IDNToUnicode);
 
 // A helper class for IDN Spoof checking, used to ensure that no IDN input is
 // spoofable per Chromium's standard of spoofability. For a more thorough
@@ -59,6 +61,10 @@
   // Cyrillic letters that look like ASCII Latin letters.
   bool IsMadeOfLatinAlikeCyrillic(const icu::UnicodeString& label);
 
+  // Used for unit tests.
+  static void RestoreTopDomainGraphToDefault();
+  static void SetTopDomainGraph(base::StringPiece domain_graph);
+
   USpoofChecker* checker_;
   icu::UnicodeSet deviation_characters_;
   icu::UnicodeSet non_ascii_latin_letters_;
@@ -70,6 +76,7 @@
   std::unique_ptr<icu::Transliterator> diacritic_remover_;
   std::unique_ptr<icu::Transliterator> extra_confusable_mapper_;
 
+  FRIEND_TEST_ALL_PREFIXES(UrlFormatterTest, IDNToUnicode);
   IDNSpoofChecker(const IDNSpoofChecker&) = delete;
   void operator=(const IDNSpoofChecker&) = delete;
 };
diff --git a/components/url_formatter/top_domains/BUILD.gn b/components/url_formatter/top_domains/BUILD.gn
index 67719cd..d8c9771 100644
--- a/components/url_formatter/top_domains/BUILD.gn
+++ b/components/url_formatter/top_domains/BUILD.gn
@@ -6,6 +6,7 @@
   script = "//net/tools/dafsa/make_dafsa.py"
   sources = [
     "alexa_skeletons.gperf",
+    "test_skeletons.gperf",
   ]
   outputs = [
     "${target_gen_dir}/{{source_name_part}}-inc.cc",
diff --git a/components/url_formatter/top_domains/README b/components/url_formatter/top_domains/README
index 137cdec..fa54f1a 100644
--- a/components/url_formatter/top_domains/README
+++ b/components/url_formatter/top_domains/README
@@ -14,3 +14,11 @@
 
   $ ninja -C $build_outdir make_top_domain_gperf
   $ $build_outdir/make_top_domain_gperf
+
+* test_domains.list
+  A list of domains to use in IDNToUnicode test instead of the actual
+  alexa top dmain. Manually edited to match what's in IDNToUnicode test.
+
+* test_skeletons.gperf
+  Generated out of test_domains.list along with alexa_skeletons.gperf
+  by make_top_domain_gperf.
diff --git a/components/url_formatter/top_domains/alexa_domains.list b/components/url_formatter/top_domains/alexa_domains.list
index 62800f4..84581b4 100644
--- a/components/url_formatter/top_domains/alexa_domains.list
+++ b/components/url_formatter/top_domains/alexa_domains.list
@@ -9172,10 +9172,3 @@
 lyft.com
 ok.ru
 stripe.com
-# for testing
-digklmo68.com
-digklmo68.co.uk
-islkpx123.com
-os345.com
-woder.com
-wmhtb.com
diff --git a/components/url_formatter/top_domains/alexa_skeletons.gperf b/components/url_formatter/top_domains/alexa_skeletons.gperf
index a734ad7..97c1c2d 100644
--- a/components/url_formatter/top_domains/alexa_skeletons.gperf
+++ b/components/url_formatter/top_domains/alexa_skeletons.gperf
@@ -9182,10 +9182,4 @@
 lyft.corn, 1
 ok.ru, 1
 stripe.corn, 1
-digklrno68.corn, 1
-digklrno68.co.uk, 1
-islkpxl23.corn, 1
-os345.corn, 1
-woder.corn, 1
-wrnhtb.corn, 1
 %%
diff --git a/components/url_formatter/top_domains/make_alexa_top_list.py b/components/url_formatter/top_domains/make_alexa_top_list.py
index d0d5e03..9877ec3 100755
--- a/components/url_formatter/top_domains/make_alexa_top_list.py
+++ b/components/url_formatter/top_domains/make_alexa_top_list.py
@@ -49,8 +49,3 @@
                  "uber.com", "lyft.com", "ok.ru", "stripe.com"]:
     if domain not in domains:
       outfile.write(domain + "\n")
-
-  # Add a few made-up domains for testing.
-  outfile.write("# for testing\ndigklmo68.com\ndigklmo68.co.uk\n")
-  outfile.write("islkpx123.com\n")
-  outfile.write("os345.com\nwoder.com\nwmhtb.com\n")
diff --git a/components/url_formatter/top_domains/make_top_domain_gperf.cc b/components/url_formatter/top_domains/make_top_domain_gperf.cc
index bd02c12b..c638b03 100644
--- a/components/url_formatter/top_domains/make_top_domain_gperf.cc
+++ b/components/url_formatter/top_domains/make_top_domain_gperf.cc
@@ -4,6 +4,7 @@
 
 #include <algorithm>
 #include <iostream>
+#include <memory>
 #include <sstream>
 #include <string>
 #include <vector>
@@ -49,16 +50,9 @@
   return succeeded;
 }
 
-int main(int argc, const char** argv) {
-  if (argc != 1) {
-    std::cerr << "Generates the list of top domain skeletons to use as input to"
-                 "\nbase/dafsa/make_dafsa.py.\nUsage: "
-              << argv[0] << '\n';
-    return 1;
-  }
-
-  base::i18n::InitializeICU();
-  base::FilePath input_file = GetPath("alexa_domains.list");
+int GenerateDasfa(const char* input_file_name,
+                  const USpoofChecker* spoof_checker) {
+  base::FilePath input_file = GetPath(input_file_name);
   std::string input_content;
   if (!base::ReadFileToString(input_file, &input_content)) {
     std::cerr << "Failed to read the input file " << input_file.AsUTF8Unsafe()
@@ -66,14 +60,6 @@
     return 1;
   }
 
-  UErrorCode status = U_ZERO_ERROR;
-  USpoofChecker* spoof_checker = uspoof_open(&status);
-  if (U_FAILURE(status)) {
-    std::cerr << "Failed to create an ICU uspoof_checker due to "
-              << u_errorName(status) << ".\n";
-    return 1;
-  }
-
   std::stringstream input(input_content);
   std::string output =
       R"(// Copyright 2017 The Chromium Authors. All rights reserved.
@@ -111,7 +97,12 @@
 
   output += "%%\n";
 
-  if (!WriteToFile(output, "alexa_skeletons.gperf"))
+  std::string output_file_name(input_file_name);
+  base::ReplaceSubstringsAfterOffset(&output_file_name, 0, "domain",
+                                     "skeleton");
+  base::ReplaceSubstringsAfterOffset(&output_file_name, 0, "list", "gperf");
+
+  if (!WriteToFile(output, output_file_name))
     return 1;
 
   std::cout << "The first domain with the largest number of labels is "
@@ -120,3 +111,24 @@
 
   return 0;
 }
+
+int main(int argc, const char** argv) {
+  if (argc != 1) {
+    std::cerr << "Generates the list of top domain skeletons to use as input to"
+                 "\nbase/dafsa/make_dafsa.py.\nUsage: "
+              << argv[0] << '\n';
+    return 1;
+  }
+
+  base::i18n::InitializeICU();
+  UErrorCode status = U_ZERO_ERROR;
+  std::unique_ptr<USpoofChecker, decltype(&uspoof_close)> spoof_checker(
+      uspoof_open(&status), &uspoof_close);
+  if (U_FAILURE(status)) {
+    std::cerr << "Failed to create an ICU uspoof_checker due to "
+              << u_errorName(status) << ".\n";
+    return 1;
+  }
+  GenerateDasfa("alexa_domains.list", spoof_checker.get());
+  GenerateDasfa("test_domains.list", spoof_checker.get());
+}
diff --git a/components/url_formatter/top_domains/test_domains.list b/components/url_formatter/top_domains/test_domains.list
new file mode 100644
index 0000000..d371f60
--- /dev/null
+++ b/components/url_formatter/top_domains/test_domains.list
@@ -0,0 +1,6 @@
+digklmo68.com
+digklmo68.co.uk
+islkpx123.com
+os345.com
+woder.com
+wmhtb.com
diff --git a/components/url_formatter/top_domains/test_skeletons.gperf b/components/url_formatter/top_domains/test_skeletons.gperf
new file mode 100644
index 0000000..4773733e
--- /dev/null
+++ b/components/url_formatter/top_domains/test_skeletons.gperf
@@ -0,0 +1,17 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file is generated by components/url_formatter/make_top_domain_gperf.cc
+// DO NOT MANUALLY EDIT!
+
+// Each entry is the skeleton of a top domain for the confusability check
+// in components/url_formatter/url_formatter.cc.
+%%
+digklrno68.corn, 1
+digklrno68.co.uk, 1
+islkpxl23.corn, 1
+os345.corn, 1
+woder.corn, 1
+wrnhtb.corn, 1
+%%
diff --git a/components/url_formatter/url_formatter_unittest.cc b/components/url_formatter/url_formatter_unittest.cc
index 4a75059d..6fd3ece5 100644
--- a/components/url_formatter/url_formatter_unittest.cc
+++ b/components/url_formatter/url_formatter_unittest.cc
@@ -11,8 +11,10 @@
 
 #include "base/macros.h"
 #include "base/strings/string_number_conversions.h"
+#include "base/strings/string_piece.h"
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
+#include "components/url_formatter/idn_spoof_checker.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "url/gurl.h"
 
@@ -264,13 +266,22 @@
     // U+0131 (dotless i) followed by U+0307
     {"xn--pxel-lza43z.com", L"p\x0131\x0307xel.com", false},
     // j followed by U+0307 (combining dot above)
-    {"xn--jack-qwc.com", L"j\x0307" L"ack.com", false},
+    {"xn--jack-qwc.com",
+     L"j\x0307"
+     L"ack.com",
+     false},
     // l followed by U+0307
-    {"xn--lace-qwc.com", L"l\x0307" L"ace.com", false},
+    {"xn--lace-qwc.com",
+     L"l\x0307"
+     L"ace.com",
+     false},
 
     // Do not allow a combining mark after dotless i/j.
     {"xn--pxel-lza29y.com", L"p\x0131\x0300xel.com", false},
-    {"xn--ack-gpb42h.com", L"\x0237\x0301" L"ack.com", false},
+    {"xn--ack-gpb42h.com",
+     L"\x0237\x0301"
+     L"ack.com",
+     false},
 
     // Mixed script confusable
     // google with Armenian Small Letter Oh(U+0585)
@@ -399,7 +410,7 @@
      false},                                                 // digklmoб8.com
     {"xn--digklmo6-7yr.com", L"digklmo6\x09ea.com", false},  // digklmo6৪.com
 
-    // 'islkpx123.com' is listed for unitest in the top domain list.
+    // 'islkpx123.com' is in the test domain list.
     // 'іѕӏкрх123' can look like 'islkpx123' in some fonts.
     {"xn--123-bed4a4a6hh40i.com",
      L"\x0456\x0455\x04cf\x043a\x0440\x0445"
@@ -413,11 +424,17 @@
     // шмнтв.com
     {"xn--b1atdu1a.com", L"\x0448\x043c\x043d\x0442\x0432.com", false},
     // ഠട345.com
-    {"xn--345-jtke.com", L"\x0d20\x0d1f" L"345.com", false},
+    {"xn--345-jtke.com",
+     L"\x0d20\x0d1f"
+     L"345.com",
+     false},
 
     // At one point the skeleton of 'w' was 'vv', ensure that
     // that it's treated as 'w'.
-    {"xn--wder-qqa.com", L"w\x00f3" L"der.com", false},
+    {"xn--wder-qqa.com",
+     L"w\x00f3"
+     L"der.com",
+     false},
 
     // Mixed digits: the first two will also fail mixed script test
     // Latin + ASCII digit + Deva digit
@@ -714,7 +731,10 @@
     // Latin Ext B - Pinyin: ǔnion.com
     {"xn--nion-unb.com", L"\x01d4nion.com", false},
     // Latin Ext C: ⱴase.com
-    {"xn--ase-7z0b.com", L"\x2c74" L"ase.com", false},
+    {"xn--ase-7z0b.com",
+     L"\x2c74"
+     L"ase.com",
+     false},
     // Latin Ext D: ꝴode.com
     {"xn--ode-ut3l.com", L"\xa774ode.com", false},
     // Latin Ext Additional: ḷily.com
@@ -778,7 +798,15 @@
                 std::string::npos, formatted_url);
 }
 
+namespace test {
+#include "components/url_formatter/top_domains/test_skeletons-inc.cc"
+}
+
+}  // namespace
+
 TEST(UrlFormatterTest, IDNToUnicode) {
+  IDNSpoofChecker::SetTopDomainGraph(base::StringPiece(
+      reinterpret_cast<const char*>(test::kDafsa), sizeof(test::kDafsa)));
   for (size_t i = 0; i < arraysize(idn_cases); i++) {
     base::string16 output(IDNToUnicode(idn_cases[i].input));
     base::string16 expected(idn_cases[i].unicode_allowed
@@ -787,6 +815,7 @@
     EXPECT_EQ(expected, output) << "input # " << i << ": \""
                                 << idn_cases[i].input << "\"";
   }
+  IDNSpoofChecker::RestoreTopDomainGraphToDefault();
 }
 
 TEST(UrlFormatterTest, FormatUrl) {
@@ -1457,6 +1486,4 @@
                        strip_trivial_subdomains_from_idn_offsets);
 }
 
-}  // namespace
-
 }  // namespace url_formatter
diff --git a/content/browser/permissions/permission_service_context.cc b/content/browser/permissions/permission_service_context.cc
index e4f237e..e115a1a 100644
--- a/content/browser/permissions/permission_service_context.cc
+++ b/content/browser/permissions/permission_service_context.cc
@@ -72,7 +72,16 @@
 
 void PermissionServiceContext::CreateService(
     blink::mojom::PermissionServiceRequest request) {
-  services_.AddBinding(std::make_unique<PermissionServiceImpl>(this),
+  DCHECK(render_frame_host_);
+  services_.AddBinding(std::make_unique<PermissionServiceImpl>(
+                           this, render_frame_host_->GetLastCommittedOrigin()),
+                       std::move(request));
+}
+
+void PermissionServiceContext::CreateServiceForWorker(
+    blink::mojom::PermissionServiceRequest request,
+    const url::Origin& origin) {
+  services_.AddBinding(std::make_unique<PermissionServiceImpl>(this, origin),
                        std::move(request));
 }
 
diff --git a/content/browser/permissions/permission_service_context.h b/content/browser/permissions/permission_service_context.h
index 0fa8254..9aaf008 100644
--- a/content/browser/permissions/permission_service_context.h
+++ b/content/browser/permissions/permission_service_context.h
@@ -33,6 +33,8 @@
   ~PermissionServiceContext() override;
 
   void CreateService(blink::mojom::PermissionServiceRequest request);
+  void CreateServiceForWorker(blink::mojom::PermissionServiceRequest request,
+                              const url::Origin& origin);
 
   void CreateSubscription(PermissionType permission_type,
                           const url::Origin& origin,
@@ -51,6 +53,10 @@
  private:
   class PermissionSubscription;
 
+  void CreateServiceForWorkerImpl(
+      blink::mojom::PermissionServiceRequest request,
+      const url::Origin& origin);
+
   // WebContentsObserver
   void RenderFrameHostChanged(RenderFrameHost* old_host,
                               RenderFrameHost* new_host) override;
diff --git a/content/browser/permissions/permission_service_impl.cc b/content/browser/permissions/permission_service_impl.cc
index 97e3e8b..14a128a0 100644
--- a/content/browser/permissions/permission_service_impl.cc
+++ b/content/browser/permissions/permission_service_impl.cc
@@ -173,8 +173,9 @@
   std::vector<PermissionStatus> results_;
 };
 
-PermissionServiceImpl::PermissionServiceImpl(PermissionServiceContext* context)
-    : context_(context), weak_factory_(this) {}
+PermissionServiceImpl::PermissionServiceImpl(PermissionServiceContext* context,
+                                             const url::Origin& origin)
+    : context_(context), origin_(origin), weak_factory_(this) {}
 
 PermissionServiceImpl::~PermissionServiceImpl() {
   BrowserContext* browser_context = context_->GetBrowserContext();
@@ -196,19 +197,17 @@
 
 void PermissionServiceImpl::RequestPermission(
     PermissionDescriptorPtr permission,
-    const url::Origin& origin,
     bool user_gesture,
     PermissionStatusCallback callback) {
   std::vector<PermissionDescriptorPtr> permissions;
   permissions.push_back(std::move(permission));
-  RequestPermissions(std::move(permissions), origin, user_gesture,
+  RequestPermissions(std::move(permissions), user_gesture,
                      base::BindOnce(&PermissionRequestResponseCallbackWrapper,
                                     base::Passed(&callback)));
 }
 
 void PermissionServiceImpl::RequestPermissions(
     std::vector<PermissionDescriptorPtr> permissions,
-    const url::Origin& origin,
     bool user_gesture,
     RequestPermissionsCallback callback) {
   // This condition is valid if the call is coming from a ChildThread instead of
@@ -226,7 +225,7 @@
       !browser_context->GetPermissionManager()) {
     std::vector<PermissionStatus> result(permissions.size());
     for (size_t i = 0; i < permissions.size(); ++i)
-      result[i] = GetPermissionStatus(permissions[i], origin);
+      result[i] = GetPermissionStatus(permissions[i]);
     std::move(callback).Run(result);
     return;
   }
@@ -248,7 +247,7 @@
 
   int pending_request_id = pending_requests_.Add(std::move(pending_request));
   int id = browser_context->GetPermissionManager()->RequestPermissions(
-      request_types, context_->render_frame_host(), origin.GetURL(),
+      request_types, context_->render_frame_host(), origin_.GetURL(),
       user_gesture,
       base::Bind(&PermissionServiceImpl::OnRequestPermissionsResponse,
                  weak_factory_.GetWeakPtr(), pending_request_id));
@@ -285,19 +284,16 @@
 }
 
 void PermissionServiceImpl::HasPermission(PermissionDescriptorPtr permission,
-                                          const url::Origin& origin,
                                           PermissionStatusCallback callback) {
-  std::move(callback).Run(GetPermissionStatus(permission, origin));
+  std::move(callback).Run(GetPermissionStatus(permission));
 }
 
 void PermissionServiceImpl::RevokePermission(
     PermissionDescriptorPtr permission,
-    const url::Origin& origin,
     PermissionStatusCallback callback) {
   PermissionType permission_type =
       PermissionDescriptorToPermissionType(permission);
-  PermissionStatus status =
-      GetPermissionStatusFromType(permission_type, origin);
+  PermissionStatus status = GetPermissionStatusFromType(permission_type);
 
   // Resetting the permission should only be possible if the permission is
   // already granted.
@@ -306,36 +302,33 @@
     return;
   }
 
-  ResetPermissionStatus(permission_type, origin);
+  ResetPermissionStatus(permission_type);
 
-  std::move(callback).Run(GetPermissionStatusFromType(permission_type, origin));
+  std::move(callback).Run(GetPermissionStatusFromType(permission_type));
 }
 
 void PermissionServiceImpl::AddPermissionObserver(
     PermissionDescriptorPtr permission,
-    const url::Origin& origin,
     PermissionStatus last_known_status,
     PermissionObserverPtr observer) {
-  PermissionStatus current_status = GetPermissionStatus(permission, origin);
+  PermissionStatus current_status = GetPermissionStatus(permission);
   if (current_status != last_known_status) {
     observer->OnPermissionStatusChange(current_status);
     last_known_status = current_status;
   }
 
   context_->CreateSubscription(PermissionDescriptorToPermissionType(permission),
-                               origin, std::move(observer));
+                               origin_, std::move(observer));
 }
 
 PermissionStatus PermissionServiceImpl::GetPermissionStatus(
-    const PermissionDescriptorPtr& permission,
-    const url::Origin& origin) {
+    const PermissionDescriptorPtr& permission) {
   return GetPermissionStatusFromType(
-      PermissionDescriptorToPermissionType(permission), origin);
+      PermissionDescriptorToPermissionType(permission));
 }
 
 PermissionStatus PermissionServiceImpl::GetPermissionStatusFromType(
-    PermissionType type,
-    const url::Origin& origin) {
+    PermissionType type) {
   BrowserContext* browser_context = context_->GetBrowserContext();
   if (!browser_context)
     return PermissionStatus::DENIED;
@@ -349,16 +342,15 @@
     return PermissionStatus::DENIED;
   }
 
-  GURL requesting_origin(origin.Serialize());
-  // If the embedding_origin is empty we'll use |origin| instead.
+  GURL requesting_origin(origin_.GetURL());
+  // If the embedding_origin is empty we'll use |origin_| instead.
   GURL embedding_origin = context_->GetEmbeddingOrigin();
   return browser_context->GetPermissionManager()->GetPermissionStatus(
       type, requesting_origin,
       embedding_origin.is_empty() ? requesting_origin : embedding_origin);
 }
 
-void PermissionServiceImpl::ResetPermissionStatus(PermissionType type,
-                                                  const url::Origin& origin) {
+void PermissionServiceImpl::ResetPermissionStatus(PermissionType type) {
   BrowserContext* browser_context = context_->GetBrowserContext();
   if (!browser_context)
     return;
@@ -366,8 +358,8 @@
   if (!browser_context->GetPermissionManager())
     return;
 
-  GURL requesting_origin(origin.Serialize());
-  // If the embedding_origin is empty we'll use |origin| instead.
+  GURL requesting_origin(origin_.GetURL());
+  // If the embedding_origin is empty we'll use |origin_| instead.
   GURL embedding_origin = context_->GetEmbeddingOrigin();
   browser_context->GetPermissionManager()->ResetPermission(
       type, requesting_origin,
diff --git a/content/browser/permissions/permission_service_impl.h b/content/browser/permissions/permission_service_impl.h
index 6782648..6e0c9bc 100644
--- a/content/browser/permissions/permission_service_impl.h
+++ b/content/browser/permissions/permission_service_impl.h
@@ -28,7 +28,8 @@
 class CONTENT_EXPORT PermissionServiceImpl
     : public blink::mojom::PermissionService {
  public:
-  PermissionServiceImpl(PermissionServiceContext* context);
+  PermissionServiceImpl(PermissionServiceContext* context,
+                        const url::Origin& origin);
   ~PermissionServiceImpl() override;
 
  private:
@@ -42,23 +43,18 @@
 
   // blink::mojom::PermissionService.
   void HasPermission(blink::mojom::PermissionDescriptorPtr permission,
-                     const url::Origin& origin,
                      PermissionStatusCallback callback) override;
   void RequestPermission(blink::mojom::PermissionDescriptorPtr permission,
-                         const url::Origin& origin,
                          bool user_gesture,
                          PermissionStatusCallback callback) override;
   void RequestPermissions(
       std::vector<blink::mojom::PermissionDescriptorPtr> permissions,
-      const url::Origin& origin,
       bool user_gesture,
       RequestPermissionsCallback callback) override;
   void RevokePermission(blink::mojom::PermissionDescriptorPtr permission,
-                        const url::Origin& origin,
                         PermissionStatusCallback callback) override;
   void AddPermissionObserver(
       blink::mojom::PermissionDescriptorPtr permission,
-      const url::Origin& origin,
       blink::mojom::PermissionStatus last_known_status,
       blink::mojom::PermissionObserverPtr observer) override;
 
@@ -67,16 +63,15 @@
       const std::vector<blink::mojom::PermissionStatus>& result);
 
   blink::mojom::PermissionStatus GetPermissionStatus(
-      const blink::mojom::PermissionDescriptorPtr& permission,
-      const url::Origin& origin);
+      const blink::mojom::PermissionDescriptorPtr& permission);
   blink::mojom::PermissionStatus GetPermissionStatusFromType(
-      PermissionType type,
-      const url::Origin& origin);
-  void ResetPermissionStatus(PermissionType type, const url::Origin& origin);
+      PermissionType type);
+  void ResetPermissionStatus(PermissionType type);
 
   RequestsMap pending_requests_;
   // context_ owns |this|.
   PermissionServiceContext* context_;
+  const url::Origin origin_;
   base::WeakPtrFactory<PermissionServiceImpl> weak_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(PermissionServiceImpl);
diff --git a/content/browser/permissions/permission_service_impl_unittest.cc b/content/browser/permissions/permission_service_impl_unittest.cc
index 23ecc12..79ac72a 100644
--- a/content/browser/permissions/permission_service_impl_unittest.cc
+++ b/content/browser/permissions/permission_service_impl_unittest.cc
@@ -68,7 +68,8 @@
         ->SetPermissionManager(std::make_unique<TestPermissionManager>());
     NavigateAndCommit(origin_.GetURL());
     service_context_.reset(new PermissionServiceContext(main_rfh()));
-    service_impl_.reset(new PermissionServiceImpl(service_context_.get()));
+    service_impl_.reset(
+        new PermissionServiceImpl(service_context_.get(), origin_));
   }
 
   void TearDown() override {
@@ -95,7 +96,7 @@
         base::Bind(&PermissionServiceImplTest::PermissionStatusCallback,
                    base::Unretained(this));
     service_impl_->HasPermission(CreatePermissionDescriptor(permission),
-                                 origin_, callback);
+                                 callback);
     EXPECT_EQ(1u, last_permission_statuses_.size());
     return last_permission_statuses_[0];
   }
@@ -108,7 +109,7 @@
     base::Callback<void(const std::vector<PermissionStatus>&)> callback =
         base::Bind(&PermissionServiceImplTest::RequestPermissionsCallback,
                    base::Unretained(this));
-    service_impl_->RequestPermissions(std::move(descriptors), origin_,
+    service_impl_->RequestPermissions(std::move(descriptors),
                                       /*user_gesture=*/false, callback);
     EXPECT_EQ(permissions.size(), last_permission_statuses_.size());
     return last_permission_statuses_;
diff --git a/content/browser/renderer_interface_binders.cc b/content/browser/renderer_interface_binders.cc
index bb4e0169..eecfa5e3 100644
--- a/content/browser/renderer_interface_binders.cc
+++ b/content/browser/renderer_interface_binders.cc
@@ -122,7 +122,7 @@
                     RenderProcessHost* host, const url::Origin& origin) {
         static_cast<RenderProcessHostImpl*>(host)
             ->permission_service_context()
-            .CreateService(std::move(request));
+            .CreateServiceForWorker(std::move(request), origin);
       }));
   parameterized_binder_registry_.AddInterface(base::BindRepeating(
       [](blink::mojom::LockManagerRequest request, RenderProcessHost* host,
diff --git a/content/public/app/mojo/content_renderer_manifest.json b/content/public/app/mojo/content_renderer_manifest.json
index 16aba63..18c1232f 100644
--- a/content/public/app/mojo/content_renderer_manifest.json
+++ b/content/public/app/mojo/content_renderer_manifest.json
@@ -31,7 +31,6 @@
         "device": [
           "device:power_monitor",
           "device:screen_orientation",
-          "device:sensors",
           "device:time_zone_monitor"
         ],
         "ui": [
diff --git a/content/renderer/input/render_widget_input_handler.cc b/content/renderer/input/render_widget_input_handler.cc
index 0b503559..04af76f 100644
--- a/content/renderer/input/render_widget_input_handler.cc
+++ b/content/renderer/input/render_widget_input_handler.cc
@@ -330,10 +330,14 @@
     const WebGestureEvent& gesture_event =
         static_cast<const WebGestureEvent&>(input_event);
     if (gesture_event.source_device == blink::kWebGestureDeviceTouchpad) {
-      delegate_->ObserveGestureEventAndResult(
-          gesture_event,
+      gfx::Vector2dF latest_overscroll_delta =
           event_overscroll ? event_overscroll->latest_overscroll_delta
-                           : gfx::Vector2dF(),
+                           : gfx::Vector2dF();
+      cc::OverscrollBehavior overscroll_behavior =
+          event_overscroll ? event_overscroll->overscroll_behavior
+                           : cc::OverscrollBehavior();
+      delegate_->ObserveGestureEventAndResult(
+          gesture_event, latest_overscroll_delta, overscroll_behavior,
           processed != WebInputEventResult::kNotHandled);
     }
   }
diff --git a/content/renderer/input/render_widget_input_handler_delegate.h b/content/renderer/input/render_widget_input_handler_delegate.h
index 3349e71..b9ae518 100644
--- a/content/renderer/input/render_widget_input_handler_delegate.h
+++ b/content/renderer/input/render_widget_input_handler_delegate.h
@@ -36,6 +36,7 @@
   virtual void ObserveGestureEventAndResult(
       const blink::WebGestureEvent& gesture_event,
       const gfx::Vector2dF& unused_delta,
+      const cc::OverscrollBehavior& overscroll_behavior,
       bool event_processed) = 0;
 
   // Notifies that a key event was just handled.
diff --git a/content/renderer/media/media_permission_dispatcher.cc b/content/renderer/media/media_permission_dispatcher.cc
index eeb8742b..91af4d0 100644
--- a/content/renderer/media/media_permission_dispatcher.cc
+++ b/content/renderer/media/media_permission_dispatcher.cc
@@ -68,6 +68,7 @@
   OnConnectionError();
 }
 
+// TODO(crbug.com/793684): |security_origin| is no longer used; remove it.
 void MediaPermissionDispatcher::HasPermission(
     Type type,
     const GURL& security_origin,
@@ -88,11 +89,11 @@
 
   GetPermissionService()->HasPermission(
       MediaPermissionTypeToPermissionDescriptor(type),
-      url::Origin::Create(security_origin),
       base::BindOnce(&MediaPermissionDispatcher::OnPermissionStatus, weak_ptr_,
                      request_id));
 }
 
+// TODO(crbug.com/793684): |security_origin| is no longer used; remove it.
 void MediaPermissionDispatcher::RequestPermission(
     Type type,
     const GURL& security_origin,
@@ -113,7 +114,6 @@
 
   GetPermissionService()->RequestPermission(
       MediaPermissionTypeToPermissionDescriptor(type),
-      url::Origin::Create(security_origin),
       blink::WebUserGestureIndicator::IsProcessingUserGesture(),
       base::BindOnce(&MediaPermissionDispatcher::OnPermissionStatus, weak_ptr_,
                      request_id));
diff --git a/content/renderer/render_widget.cc b/content/renderer/render_widget.cc
index 9b687ec..0dc04e7 100644
--- a/content/renderer/render_widget.cc
+++ b/content/renderer/render_widget.cc
@@ -1102,6 +1102,7 @@
 void RenderWidget::ObserveGestureEventAndResult(
     const blink::WebGestureEvent& gesture_event,
     const gfx::Vector2dF& unused_delta,
+    const cc::OverscrollBehavior& overscroll_behavior,
     bool event_processed) {
   if (!compositor_deps_->IsElasticOverscrollEnabled())
     return;
@@ -1110,6 +1111,7 @@
   scroll_result.did_scroll = event_processed;
   scroll_result.did_overscroll_root = !unused_delta.IsZero();
   scroll_result.unused_scroll_delta = unused_delta;
+  scroll_result.overscroll_behavior = overscroll_behavior;
 
   RenderThreadImpl* render_thread = RenderThreadImpl::current();
   InputHandlerManager* input_handler_manager =
diff --git a/content/renderer/render_widget.h b/content/renderer/render_widget.h
index 78a031f4..e0b8c81 100644
--- a/content/renderer/render_widget.h
+++ b/content/renderer/render_widget.h
@@ -22,6 +22,7 @@
 #include "base/observer_list.h"
 #include "base/time/time.h"
 #include "build/build_config.h"
+#include "cc/input/overscroll_behavior.h"
 #include "cc/input/touch_action.h"
 #include "components/viz/common/surfaces/local_surface_id.h"
 #include "content/common/content_export.h"
@@ -261,9 +262,11 @@
 
   // RenderWidgetInputHandlerDelegate
   void FocusChangeComplete() override;
-  void ObserveGestureEventAndResult(const blink::WebGestureEvent& gesture_event,
-                                    const gfx::Vector2dF& unused_delta,
-                                    bool event_processed) override;
+  void ObserveGestureEventAndResult(
+      const blink::WebGestureEvent& gesture_event,
+      const gfx::Vector2dF& unused_delta,
+      const cc::OverscrollBehavior& overscroll_behavior,
+      bool event_processed) override;
 
   void OnDidHandleKeyEvent() override;
   void OnDidOverscroll(const ui::DidOverscrollParams& params) override;
diff --git a/content/shell/test_runner/pixel_dump.cc b/content/shell/test_runner/pixel_dump.cc
index 847aa82..bf55f681 100644
--- a/content/shell/test_runner/pixel_dump.cc
+++ b/content/shell/test_runner/pixel_dump.cc
@@ -153,10 +153,10 @@
                      base::OnceCallback<void(const SkBitmap&)> callback) {
   DCHECK(web_frame);
   DCHECK(!callback.is_null());
-  base::ThreadTaskRunnerHandle::Get()->PostTask(
-      FROM_HERE,
-      base::BindOnce(&CapturePixelsForPrinting, base::Unretained(web_frame),
-                     base::Passed(std::move(callback))));
+  web_frame->GetTaskRunner(blink::TaskType::kUnthrottled)
+      ->PostTask(FROM_HERE, base::BindOnce(&CapturePixelsForPrinting,
+                                           base::Unretained(web_frame),
+                                           base::Passed(std::move(callback))));
 }
 
 base::OnceCallback<void(const SkBitmap&)>
diff --git a/mojo/public/cpp/bindings/lib/wtf_clone_equals_util.h b/mojo/public/cpp/bindings/lib/wtf_clone_equals_util.h
index f18274f..d801daf 100644
--- a/mojo/public/cpp/bindings/lib/wtf_clone_equals_util.h
+++ b/mojo/public/cpp/bindings/lib/wtf_clone_equals_util.h
@@ -20,7 +20,7 @@
 struct CloneTraits<WTF::Vector<T>, false> {
   static WTF::Vector<T> Clone(const WTF::Vector<T>& input) {
     WTF::Vector<T> result;
-    result.reserveCapacity(input.size());
+    result.ReserveCapacity(input.size());
     for (const auto& element : input)
       result.push_back(mojo::Clone(element));
 
@@ -32,9 +32,9 @@
 struct CloneTraits<WTF::HashMap<K, V>, false> {
   static WTF::HashMap<K, V> Clone(const WTF::HashMap<K, V>& input) {
     WTF::HashMap<K, V> result;
-    auto input_end = input.end();
-    for (auto it = input.begin(); it != input_end; ++it)
-      result.add(mojo::Clone(it->key), mojo::Clone(it->value));
+    for (const auto& element : input)
+      result.insert(mojo::Clone(element.key), mojo::Clone(element.value));
+
     return result;
   }
 };
@@ -45,7 +45,7 @@
     if (a.size() != b.size())
       return false;
     for (size_t i = 0; i < a.size(); ++i) {
-      if (!Equals(a[i], b[i]))
+      if (!mojo::Equals(a[i], b[i]))
         return false;
     }
     return true;
@@ -63,7 +63,7 @@
 
     for (auto iter = a.begin(); iter != a_end; ++iter) {
       auto b_iter = b.find(iter->key);
-      if (b_iter == b_end || !Equals(iter->value, b_iter->value))
+      if (b_iter == b_end || !mojo::Equals(iter->value, b_iter->value))
         return false;
     }
     return true;
diff --git a/mojo/public/cpp/bindings/tests/wtf_types_unittest.cc b/mojo/public/cpp/bindings/tests/wtf_types_unittest.cc
index 0ade901a..42c3555 100644
--- a/mojo/public/cpp/bindings/tests/wtf_types_unittest.cc
+++ b/mojo/public/cpp/bindings/tests/wtf_types_unittest.cc
@@ -237,5 +237,20 @@
   }
 }
 
+TEST_F(WTFTypesTest, NestedStruct_CloneAndEquals) {
+  auto a = blink::TestWTFStructWrapper::New();
+  a->nested_struct = blink::TestWTFStruct::New("foo", 1);
+  a->array_struct.push_back(blink::TestWTFStruct::New("bar", 2));
+  a->array_struct.push_back(blink::TestWTFStruct::New("bar", 3));
+  a->map_struct.insert(blink::TestWTFStruct::New("baz", 4),
+                       blink::TestWTFStruct::New("baz", 5));
+  auto b = a.Clone();
+  EXPECT_EQ(a, b);
+  EXPECT_EQ(2u, b->array_struct.size());
+  EXPECT_EQ(1u, b->map_struct.size());
+  EXPECT_NE(blink::TestWTFStructWrapper::New(), a);
+  EXPECT_NE(blink::TestWTFStructWrapper::New(), b);
+}
+
 }  // namespace test
 }  // namespace mojo
diff --git a/mojo/public/interfaces/bindings/tests/test_wtf_types.mojom b/mojo/public/interfaces/bindings/tests/test_wtf_types.mojom
index 183f184..22d6a67 100644
--- a/mojo/public/interfaces/bindings/tests/test_wtf_types.mojom
+++ b/mojo/public/interfaces/bindings/tests/test_wtf_types.mojom
@@ -33,6 +33,12 @@
   int32 integer;
 };
 
+struct TestWTFStructWrapper {
+  TestWTFStruct nested_struct;
+  array<TestWTFStruct> array_struct;
+  map<TestWTFStruct, TestWTFStruct> map_struct;
+};
+
 interface TestWTF {
   enum NestedEnum {
     E0,
diff --git a/mojo/public/tools/bindings/generators/cpp_templates/module.h.tmpl b/mojo/public/tools/bindings/generators/cpp_templates/module.h.tmpl
index 17001154..575b69b 100644
--- a/mojo/public/tools/bindings/generators/cpp_templates/module.h.tmpl
+++ b/mojo/public/tools/bindings/generators/cpp_templates/module.h.tmpl
@@ -76,6 +76,7 @@
 {%- else %}
 {# hash_util.h includes template specializations that should be present for
    every use of {Inlined}StructPtr. #}
+#include "mojo/public/cpp/bindings/lib/wtf_clone_equals_util.h"
 #include "mojo/public/cpp/bindings/lib/wtf_hash_util.h"
 #include "third_party/WebKit/Source/platform/wtf/HashFunctions.h"
 #include "third_party/WebKit/Source/platform/wtf/Optional.h"
diff --git a/services/device/manifest.json b/services/device/manifest.json
index 35f09ba..f809e68 100644
--- a/services/device/manifest.json
+++ b/services/device/manifest.json
@@ -13,12 +13,6 @@
         "device:nfc": [ "device::mojom::NFCProvider" ],
         "device:power_monitor": [ "device::mojom::PowerMonitor" ],
         "device:screen_orientation": [ "device::mojom::ScreenOrientationListener" ],
-        "device:sensors": [
-          "device::mojom::LightSensor",
-          "device::mojom::MotionSensor",
-          "device::mojom::OrientationAbsoluteSensor",
-          "device::mojom::OrientationSensor"
-        ],
         "device:serial": [
           "device::mojom::SerialDeviceEnumerator",
           "device::mojom::SerialIoHandler"
diff --git a/testing/buildbot/chromium.fyi.json b/testing/buildbot/chromium.fyi.json
index 1716b70..a0969d9 100644
--- a/testing/buildbot/chromium.fyi.json
+++ b/testing/buildbot/chromium.fyi.json
@@ -9,111 +9,6 @@
       {
         "args": [
           "--shared-prefs-file=//chrome/android/shared_preference_files/test/vr_cardboard_skipdon_setupcomplete.json",
-          "--additional-apk=//third_party/gvr-android-sdk/test-apks/vr_services/vr_services_current.apk",
-          "--gs-results-bucket=chromium-result-details"
-        ],
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "chrome_public_test_vr_apk"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
-        "name": "chrome_public_test_vr_apk-nonddready-cardboard-current-kitkat",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "cipd_packages": [
-            {
-              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
-              "location": "bin",
-              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
-            }
-          ],
-          "dimension_sets": [
-            {
-              "device_os": "KTU84P",
-              "device_type": "hammerhead"
-            }
-          ],
-          "hard_timeout": 960
-        },
-        "test": "chrome_public_test_vr_apk"
-      },
-      {
-        "args": [
-          "--shared-prefs-file=//chrome/android/shared_preference_files/test/vr_cardboard_skipdon_setupcomplete.json",
-          "--additional-apk=//third_party/gvr-android-sdk/test-apks/vr_services/vr_services_current.apk",
-          "--gs-results-bucket=chromium-result-details"
-        ],
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "chrome_public_test_vr_apk"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
-        "name": "chrome_public_test_vr_apk-nonddready-cardboard-current-lollipop",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "cipd_packages": [
-            {
-              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
-              "location": "bin",
-              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
-            }
-          ],
-          "dimension_sets": [
-            {
-              "device_os": "LMY48I",
-              "device_type": "hammerhead"
-            }
-          ],
-          "hard_timeout": 960
-        },
-        "test": "chrome_public_test_vr_apk"
-      },
-      {
-        "args": [
-          "--shared-prefs-file=//chrome/android/shared_preference_files/test/vr_cardboard_skipdon_setupcomplete.json",
-          "--additional-apk=//third_party/gvr-android-sdk/test-apks/vr_services/vr_services_current.apk",
-          "--gs-results-bucket=chromium-result-details"
-        ],
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "chrome_public_test_vr_apk"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
-        "name": "chrome_public_test_vr_apk-nonddready-cardboard-current-marshmallow",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "cipd_packages": [
-            {
-              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
-              "location": "bin",
-              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
-            }
-          ],
-          "dimension_sets": [
-            {
-              "device_os": "MMB29Q",
-              "device_type": "bullhead"
-            }
-          ],
-          "hard_timeout": 960
-        },
-        "test": "chrome_public_test_vr_apk"
-      },
-      {
-        "args": [
-          "--shared-prefs-file=//chrome/android/shared_preference_files/test/vr_cardboard_skipdon_setupcomplete.json",
           "--replace-system-package=com.google.vr.vrcore,//third_party/gvr-android-sdk/test-apks/vr_services/vr_services_current.apk",
           "--gs-results-bucket=chromium-result-details"
         ],
@@ -122,7 +17,7 @@
             "--bucket",
             "chromium-result-details",
             "--test-name",
-            "chrome_public_test_vr_apk"
+            "chrome_public_test_vr_apk-marlin-cardboard-nougat"
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
@@ -157,7 +52,7 @@
             "--bucket",
             "chromium-result-details",
             "--test-name",
-            "chrome_public_test_vr_apk"
+            "chrome_public_test_vr_apk-marlin-ddview-nougat"
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
@@ -194,7 +89,7 @@
             "--bucket",
             "chromium-result-details",
             "--test-name",
-            "chrome_public_test_vr_apk"
+            "chrome_public_test_vr_apk-marlin-ddview-nougat-donenabled"
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
@@ -219,6 +114,111 @@
         "test": "chrome_public_test_vr_apk"
       },
       {
+        "args": [
+          "--shared-prefs-file=//chrome/android/shared_preference_files/test/vr_cardboard_skipdon_setupcomplete.json",
+          "--additional-apk=//third_party/gvr-android-sdk/test-apks/vr_services/vr_services_current.apk",
+          "--gs-results-bucket=chromium-result-details"
+        ],
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
+            "chrome_public_test_vr_apk-nonddready-cardboard-current-kitkat"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
+        "name": "chrome_public_test_vr_apk-nonddready-cardboard-current-kitkat",
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "cipd_packages": [
+            {
+              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
+              "location": "bin",
+              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
+            }
+          ],
+          "dimension_sets": [
+            {
+              "device_os": "KTU84P",
+              "device_type": "hammerhead"
+            }
+          ],
+          "hard_timeout": 960
+        },
+        "test": "chrome_public_test_vr_apk"
+      },
+      {
+        "args": [
+          "--shared-prefs-file=//chrome/android/shared_preference_files/test/vr_cardboard_skipdon_setupcomplete.json",
+          "--additional-apk=//third_party/gvr-android-sdk/test-apks/vr_services/vr_services_current.apk",
+          "--gs-results-bucket=chromium-result-details"
+        ],
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
+            "chrome_public_test_vr_apk-nonddready-cardboard-current-lollipop"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
+        "name": "chrome_public_test_vr_apk-nonddready-cardboard-current-lollipop",
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "cipd_packages": [
+            {
+              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
+              "location": "bin",
+              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
+            }
+          ],
+          "dimension_sets": [
+            {
+              "device_os": "LMY48I",
+              "device_type": "hammerhead"
+            }
+          ],
+          "hard_timeout": 960
+        },
+        "test": "chrome_public_test_vr_apk"
+      },
+      {
+        "args": [
+          "--shared-prefs-file=//chrome/android/shared_preference_files/test/vr_cardboard_skipdon_setupcomplete.json",
+          "--additional-apk=//third_party/gvr-android-sdk/test-apks/vr_services/vr_services_current.apk",
+          "--gs-results-bucket=chromium-result-details"
+        ],
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
+            "chrome_public_test_vr_apk-nonddready-cardboard-current-marshmallow"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
+        "name": "chrome_public_test_vr_apk-nonddready-cardboard-current-marshmallow",
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "cipd_packages": [
+            {
+              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
+              "location": "bin",
+              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
+            }
+          ],
+          "dimension_sets": [
+            {
+              "device_os": "MMB29Q",
+              "device_type": "bullhead"
+            }
+          ],
+          "hard_timeout": 960
+        },
+        "test": "chrome_public_test_vr_apk"
+      },
+      {
         "swarming": {
           "can_use_on_swarming_builders": false
         },
@@ -236,6 +236,15 @@
           "--replace-system-package=com.google.vr.vrcore,//third_party/gvr-android-sdk/test-apks/vr_services/vr_services_current.apk",
           "--test-filter=WebViewWebVrTest#*"
         ],
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
+            "webview_instrumentation_test_apk-marlin-ddview-nougat"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
         "name": "webview_instrumentation_test_apk-marlin-ddview-nougat",
         "swarming": {
           "can_use_on_swarming_builders": true,
@@ -349,8 +358,7 @@
             {
               "os": "Ubuntu-14.04"
             }
-          ],
-          "shards": 1
+          ]
         }
       }
     ]
@@ -1698,17 +1706,17 @@
         "isolate_name": "telemetry_perf_unittests",
         "name": "telemetry_perf_unittests",
         "swarming": {
-          "can_use_on_swarming_builders": false,
-          "hard_timeout": 960,
-          "shards": 12
+          "can_use_on_swarming_builders": false
         }
       },
       {
+        "args": [
+          "--jobs=1"
+        ],
         "isolate_name": "telemetry_unittests",
         "name": "telemetry_unittests",
         "swarming": {
-          "can_use_on_swarming_builders": false,
-          "shards": 2
+          "can_use_on_swarming_builders": false
         }
       }
     ]
@@ -2266,17 +2274,17 @@
         "isolate_name": "telemetry_perf_unittests",
         "name": "telemetry_perf_unittests",
         "swarming": {
-          "can_use_on_swarming_builders": false,
-          "hard_timeout": 960,
-          "shards": 12
+          "can_use_on_swarming_builders": false
         }
       },
       {
+        "args": [
+          "--jobs=1"
+        ],
         "isolate_name": "telemetry_unittests",
         "name": "telemetry_unittests",
         "swarming": {
-          "can_use_on_swarming_builders": false,
-          "shards": 2
+          "can_use_on_swarming_builders": false
         }
       },
       {
@@ -4306,7 +4314,6 @@
         "test": "content_browsertests"
       },
       {
-        "name": "keyboard_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true
         },
@@ -5647,6 +5654,9 @@
         }
       },
       {
+        "args": [
+          "--jobs=1"
+        ],
         "isolate_name": "telemetry_unittests",
         "name": "telemetry_unittests",
         "swarming": {
@@ -5974,6 +5984,40 @@
   "Site Isolation Android": {
     "gtest_tests": [
       {
+        "args": [
+          "--site-per-process"
+        ],
+        "name": "site_per_process_components_browsertests",
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "device_os": "MMB29Q",
+              "device_type": "bullhead"
+            }
+          ],
+          "hard_timeout": 960
+        },
+        "test": "components_browsertests"
+      },
+      {
+        "args": [
+          "--site-per-process"
+        ],
+        "name": "site_per_process_components_unittests",
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "device_os": "MMB29Q",
+              "device_type": "bullhead"
+            }
+          ],
+          "hard_timeout": 960
+        },
+        "test": "components_unittests"
+      },
+      {
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -5989,8 +6033,8 @@
       },
       {
         "args": [
-          "--gtest-filter-file=../../testing/buildbot/filters/site-per-process.content_browsertests.filter",
-          "--site-per-process"
+          "--site-per-process",
+          "--test-launcher-filter-file=../../testing/buildbot/filters/site-per-process.content_browsertests.filter"
         ],
         "name": "site_per_process_content_browsertests",
         "swarming": {
@@ -6034,40 +6078,6 @@
           "hard_timeout": 960
         },
         "test": "content_unittests"
-      },
-      {
-        "args": [
-          "--site-per-process"
-        ],
-        "name": "site_per_process_components_browsertests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "device_os": "MMB29Q",
-              "device_type": "bullhead"
-            }
-          ],
-          "hard_timeout": 960
-        },
-        "test": "components_browsertests"
-      },
-      {
-        "args": [
-          "--site-per-process"
-        ],
-        "name": "site_per_process_components_unittests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "device_os": "MMB29Q",
-              "device_type": "bullhead"
-            }
-          ],
-          "hard_timeout": 960
-        },
-        "test": "components_unittests"
       }
     ]
   },
@@ -6395,8 +6405,7 @@
           "--gtest_filter=-SaveType/SavePageMultiFrameBrowserTest.ObjectElements/0"
         ],
         "swarming": {
-          "can_use_on_swarming_builders": false,
-          "shards": 10
+          "can_use_on_swarming_builders": false
         },
         "test": "browser_tests"
       },
@@ -7176,8 +7185,7 @@
       },
       {
         "swarming": {
-          "can_use_on_swarming_builders": false,
-          "shards": 10
+          "can_use_on_swarming_builders": false
         },
         "test": "browser_tests"
       },
diff --git a/testing/buildbot/client.v8.chromium.json b/testing/buildbot/client.v8.chromium.json
index fa8ad44c..7bcc03f2 100644
--- a/testing/buildbot/client.v8.chromium.json
+++ b/testing/buildbot/client.v8.chromium.json
@@ -1,4 +1,6 @@
 {
+  "AAAAA1 AUTOGENERATED FILE DO NOT EDIT": {},
+  "AAAAA2 See generate_buildbot_json.py to make changes": {},
   "Linux - Future": {
     "gtest_tests": [
       {
@@ -353,8 +355,7 @@
           "shards": 4
         }
       }
-    ],
-    "scripts": []
+    ]
   },
   "Linux - Future (dbg)": {
     "gtest_tests": [
@@ -661,7 +662,6 @@
           "shards": 4
         }
       }
-    ],
-    "scripts": []
+    ]
   }
 }
diff --git a/testing/buildbot/test_suite_exceptions.pyl b/testing/buildbot/test_suite_exceptions.pyl
index 3dc02ac..9daebd44 100644
--- a/testing/buildbot/test_suite_exceptions.pyl
+++ b/testing/buildbot/test_suite_exceptions.pyl
@@ -378,6 +378,28 @@
       },
     },
   },
+  # TODO(dpranke): browser_side_navigation is the default now; we should
+  # not run these at all, or flip them to renderer_side_navigation.
+  'browser_side_navigation_browser_tests': {
+    'modifications': {
+      # client.v8.chromium
+      'Linux - Future (dbg)': {
+        'swarming': {
+          'shards': 10,
+        },
+      },
+    },
+  },
+  'browser_side_navigation_interactive_ui_tests': {
+    'modifications': {
+      # client.v8.chromium
+      'Linux - Future (dbg)': {
+        'swarming': {
+          'shards': 3,
+        },
+      },
+    },
+  },
   'browser_tests': {
     'remove_from': [
       # chromium.clang
@@ -504,6 +526,12 @@
           'can_use_on_swarming_builders': False,
         },
       },
+      # client.v8.chromium
+      'Linux - Future (dbg)': {
+        'swarming': {
+          'shards':  10,
+        },
+      },
     },
   },
   'cacheinvalidation_unittests': {
@@ -1065,6 +1093,8 @@
       'Win 7 Tests x64 (1)',
       'Win10 Tests x64',
       'Win7 Tests (dbg)(1)',
+      # client.v8.chromium
+      'Linux - Future (dbg)',
     ],
   },
   'content_shell_test_apk': {
@@ -1222,6 +1252,8 @@
       # On chromium.linux, unclear why these only run on "Linux Tests".
       'Linux Tests (dbg)(1)',
       'Linux Tests (dbg)(1)(32)',
+      # client.v8.chromium
+      'Linux - Future (dbg)',
     ],
   },
   'devtools_eslint': {
@@ -1229,6 +1261,8 @@
       # On chromium.linux, unclear why these only run on "Linux Tests".
       'Linux Tests (dbg)(1)',
       'Linux Tests (dbg)(1)(32)',
+      # client.v8.chromium
+      'Linux - Future (dbg)',
     ],
   },
   'display_unittests': {
@@ -1393,6 +1427,8 @@
       'Win 7 Tests x64 (1)',
       'Win10 Tests x64',
       'Win7 Tests (dbg)(1)',
+      # client.v8.chromium
+      'Linux - Future (dbg)',
     ],
   },
   'gl_tests': {
@@ -1584,6 +1620,8 @@
       'Linux Tests (dbg)(1)(32)',
       # On chromium.mac, unclear why these aren't run on "Mac10.11 Tests".
       'Mac10.11 Tests',
+      # client.v8.chromium
+      'Linux - Future (dbg)',
     ],
   },
   'headless_unittests': {
@@ -1591,6 +1629,8 @@
       'Linux Tests (dbg)(1)(32)',
       # On chromium.mac, unclear why these aren't run on "Mac10.11 Tests".
       'Mac10.11 Tests',
+      # client.v8.chromium
+      'Linux - Future (dbg)'
     ],
   },
   'install_static_unittests': {
@@ -1702,6 +1742,12 @@
           'shards': 1,
         },
       },
+      # client.v8.chromium
+      'Linux - Future (dbg)': {
+        'swarming': {
+          'shards': 3,
+        },
+      },
     },
   },
   'ipc_tests': {
@@ -2460,6 +2506,12 @@
           'shards': 10,
         },
       },
+      # client.v8.chromium
+      'Linux - Future (dbg)': {
+        'swarming': {
+          'shards': 10,
+        },
+      },
     },
   },
   'site_per_process_content_browsertests': {
@@ -2476,6 +2528,19 @@
     'remove_from': [
       'Linux Tests (dbg)(1)(32)',
     ],
+    'modifications': {
+      'Linux - Future': {
+        'args': [
+          '--site-per-process',
+        ],
+      },
+      'Linux - Future (dbg)': {
+        # TODO(dpranke): this should be --site-per-process.
+        'args': [
+          '--site_per_process',
+        ],
+      },
+    },
   },
   'sizes': {
     'remove_from': [
@@ -2684,6 +2749,8 @@
       'Mac10.9 Tests',
       'Mac10.9 Tests (dbg)',
       'Win7 Tests (dbg)(1)',
+      # client.v8.chromium
+      'Linux - Future (dbg)',
     ],
   },
   'telemetry_unittests': {
diff --git a/testing/buildbot/test_suites.pyl b/testing/buildbot/test_suites.pyl
index 12879a0..e082e21 100644
--- a/testing/buildbot/test_suites.pyl
+++ b/testing/buildbot/test_suites.pyl
@@ -406,6 +406,146 @@
     'unit_tests': {},
   },
 
+  'client_v8_chromium_gtests': {
+    'app_shell_unittests': {},
+    'browser_tests': {
+      'swarming': {
+        'shards': 5,
+      },
+    },
+    # TODO(dpranke): browser_side_navigation is the default now; we should
+    # either not run these at all, or flip them to renderer_side_navigation.
+    'browser_side_navigation_browser_tests': {
+      'args': [
+        '--enable-browser-side-navigation',
+      ],
+      'swarming': {
+        'shards': 5,
+      },
+      'test': 'browser_tests',
+    },
+    'browser_side_navigation_components_browsertests': {
+      'args': [
+        '--enable-browser-side-navigation',
+      ],
+      'test': 'components_browsertests',
+    },
+    'browser_side_navigation_components_unittests': {
+      'args': [
+        '--enable-browser-side-navigation',
+      ],
+      'test': 'components_unittests',
+    },
+    'browser_side_navigation_content_browsertests': {
+      'args': [
+        '--enable-browser-side-navigation',
+      ],
+      'test': 'content_browsertests',
+    },
+    'browser_side_navigation_content_unittests': {
+      'args': [
+        '--enable-browser-side-navigation',
+      ],
+      'test': 'content_unittests',
+    },
+    'browser_side_navigation_extensions_browsertests': {
+      'args': [
+        '--enable-browser-side-navigation',
+      ],
+      'test': 'extensions_browsertests',
+    },
+    'browser_side_navigation_interactive_ui_tests': {
+      'args': [
+        '--enable-browser-side-navigation',
+      ],
+      'test': 'interactive_ui_tests',
+    },
+    'browser_side_navigation_unit_tests': {
+      'args': [
+        '--enable-browser-side-navigation',
+      ],
+      'test': 'unit_tests',
+    },
+    'chrome_app_unittests': {},
+    'chromedriver_unittests': {},
+    'components_browsertests': {},
+    'components_unittests': {},
+    'compositor_unittests': {},
+    'content_browsertests': {},
+    'content_unittests': {},
+    'device_unittests': {},
+    'extensions_browsertests': {},
+    'extensions_unittests': {},
+    'gcm_unit_tests': {},
+    'gin_unittests': {},
+    'google_apis_unittests': {},
+    'gpu_unittests': {},
+    'headless_browsertests': {},
+    'headless_unittests': {},
+    'interactive_ui_tests': {},
+    'jingle_unittests': {},
+    'media_blink_unittests': {},
+    'nacl_loader_unittests': {},
+    'net_unittests': {},
+    'pdf_unittests': {},
+    'ppapi_unittests': {},
+    'remoting_unittests': {},
+    'services_unittests': {},
+
+    'site_per_process_browser_tests': {
+      'args': [
+        '--site-per-process',
+        '--test-launcher-filter-file=../../testing/buildbot/filters/site-per-process.browser_tests.filter'
+      ],
+      'swarming': {
+        'shards': 5,
+      },
+      'test': 'browser_tests',
+    },
+    'site_per_process_content_browsertests': {
+      'args': [
+        '--site-per-process',
+        '--test-launcher-filter-file=../../testing/buildbot/filters/site-per-process.content_browsertests.filter'
+      ],
+      'test': 'content_browsertests',
+    },
+    'site_per_process_content_unittests': {
+      'args': [
+        '--site-per-process',
+      ],
+      'test': 'content_unittests',
+    },
+    'site_per_process_unit_tests': {
+      'test': 'unit_tests',
+    },
+    'sync_integration_tests': {},
+    'unit_tests': {},
+  },
+
+  'client_v8_chromium_isolated_scripts': {
+    'content_shell_crash_test': {},
+    'devtools_closure_compile': {},
+    'devtools_eslint': {},
+    'telemetry_gpu_unittests': {},
+    'telemetry_perf_unittests': {
+      'args': [
+        '--xvfb',
+      ],
+      'swarming': {
+        'hard_timeout': 960,
+        'shards': 12,
+      },
+    },
+    'telemetry_unittests': {
+      'args': [
+        '--jobs=1',
+      ],
+      'swarming': {
+        'shards': 4,
+      },
+    },
+  },
+
   'cronet_gtests': {
     'cronet_sample_test_apk': {
       'swarming': {
diff --git a/testing/buildbot/waterfalls.pyl b/testing/buildbot/waterfalls.pyl
index 1b25a6a..eab30a7 100644
--- a/testing/buildbot/waterfalls.pyl
+++ b/testing/buildbot/waterfalls.pyl
@@ -1249,6 +1249,23 @@
     },
   },
   {
+    'name': 'client.v8.chromium',
+    'machines': {
+      'Linux - Future': {
+        'test_suites': {
+          'gtest_tests': 'client_v8_chromium_gtests',
+          'isolated_scripts': 'client_v8_chromium_isolated_scripts',
+        },
+      },
+      'Linux - Future (dbg)': {
+        'test_suites': {
+          'gtest_tests': 'client_v8_chromium_gtests',
+          'isolated_scripts': 'client_v8_chromium_isolated_scripts',
+        },
+      },
+    },
+  },
+  {
     'name': 'client.v8.branches',
     'machines': {},
   },
diff --git a/third_party/WebKit/Source/bindings/core/v8/V8GCController.cpp b/third_party/WebKit/Source/bindings/core/v8/V8GCController.cpp
index d0596f8..5b0c09dd 100644
--- a/third_party/WebKit/Source/bindings/core/v8/V8GCController.cpp
+++ b/third_party/WebKit/Source/bindings/core/v8/V8GCController.cpp
@@ -35,6 +35,7 @@
 #include <unordered_set>
 #include "bindings/core/v8/ActiveScriptWrappable.h"
 #include "bindings/core/v8/RetainedDOMInfo.h"
+#include "bindings/core/v8/ScriptSourceCode.h"
 #include "bindings/core/v8/V8AbstractEventListener.h"
 #include "bindings/core/v8/V8BindingForCore.h"
 #include "bindings/core/v8/V8Node.h"
@@ -458,7 +459,10 @@
   builder.Append(only_minor_gc ? "true" : "false");
   builder.Append(")");
   V8ScriptRunner::CompileAndRunInternalScript(
-      script_state.get(), V8String(isolate, builder.ToString()), isolate);
+      script_state.get(),
+      ScriptSourceCode(builder.ToString(), ScriptSourceLocationType::kInternal,
+                       nullptr, KURL(), TextPosition()),
+      isolate);
   script_state->DisposePerContextData();
 }
 
diff --git a/third_party/WebKit/Source/bindings/core/v8/V8ScriptRunner.cpp b/third_party/WebKit/Source/bindings/core/v8/V8ScriptRunner.cpp
index e7dfef8..4467c9a 100644
--- a/third_party/WebKit/Source/bindings/core/v8/V8ScriptRunner.cpp
+++ b/third_party/WebKit/Source/bindings/core/v8/V8ScriptRunner.cpp
@@ -390,7 +390,7 @@
     ScriptState* script_state,
     const ScriptSourceCode& source,
     AccessControlStatus access_control_status,
-    V8CacheOptions v8_cache_options,
+    V8CacheOptions cache_options,
     const ReferrerScriptInfo& referrer_info) {
   v8::Isolate* isolate = script_state->GetIsolate();
   if (source.Source().length() >= v8::String::kMaxLength) {
@@ -398,25 +398,12 @@
     return v8::Local<v8::Script>();
   }
 
-  return CompileScript(script_state, V8String(isolate, source.Source()),
-                       source.Url(), source.SourceMapUrl(),
-                       source.StartPosition(), source.SourceLocationType(),
-                       source.Streamer(), source.CacheHandler(),
-                       access_control_status, v8_cache_options, referrer_info);
-}
+  v8::Local<v8::String> code = V8String(isolate, source.Source());
+  const String& file_name = source.Url();
+  const TextPosition& script_start_position = source.StartPosition();
+  ScriptStreamer* streamer = source.Streamer();
+  CachedMetadataHandler* cache_handler = source.CacheHandler();
 
-v8::MaybeLocal<v8::Script> V8ScriptRunner::CompileScript(
-    ScriptState* script_state,
-    v8::Local<v8::String> code,
-    const String& file_name,
-    const String& source_map_url,
-    const TextPosition& script_start_position,
-    ScriptSourceLocationType source_location_type,
-    ScriptStreamer* streamer,
-    CachedMetadataHandler* cache_handler,
-    AccessControlStatus access_control_status,
-    V8CacheOptions cache_options,
-    const ReferrerScriptInfo& referrer_info) {
   constexpr const char* kTraceEventCategoryGroup = "v8,devtools.timeline";
   TRACE_EVENT_BEGIN1(kTraceEventCategoryGroup, "v8.compile", "fileName",
                      file_name.Utf8());
@@ -426,21 +413,19 @@
 
   // NOTE: For compatibility with WebCore, ScriptSourceCode's line starts at
   // 1, whereas v8 starts at 0.
-  v8::Isolate* isolate = script_state->GetIsolate();
-
   v8::ScriptOrigin origin(
       V8String(isolate, file_name),
       v8::Integer::New(isolate, script_start_position.line_.ZeroBasedInt()),
       v8::Integer::New(isolate, script_start_position.column_.ZeroBasedInt()),
       v8::Boolean::New(isolate, access_control_status == kSharableCrossOrigin),
-      v8::Local<v8::Integer>(), V8String(isolate, source_map_url),
+      v8::Local<v8::Integer>(), V8String(isolate, source.SourceMapUrl()),
       v8::Boolean::New(isolate, access_control_status == kOpaqueResource),
       v8::False(isolate),  // is_wasm
       v8::False(isolate),  // is_module
       referrer_info.ToV8HostDefinedOptions(isolate));
 
   v8::ScriptCompiler::NoCacheReason no_handler_reason;
-  switch (source_location_type) {
+  switch (source.SourceLocationType()) {
     case ScriptSourceLocationType::kInline:
       no_handler_reason = v8::ScriptCompiler::kNoCacheBecauseInlineScript;
       break;
@@ -539,18 +524,17 @@
 
 v8::MaybeLocal<v8::Value> V8ScriptRunner::CompileAndRunInternalScript(
     ScriptState* script_state,
-    v8::Local<v8::String> source,
-    v8::Isolate* isolate,
-    const String& file_name,
-    const TextPosition& script_start_position) {
+    const ScriptSourceCode& source_code,
+    v8::Isolate* isolate) {
+  DCHECK_EQ(isolate, script_state->GetIsolate());
+
   v8::Local<v8::Script> script;
   // Use default ScriptReferrerInfo here:
   // - nonce: empty for internal script, and
   // - parser_state: always "not parser inserted" for internal scripts.
   if (!V8ScriptRunner::CompileScript(
-           script_state, source, file_name, String(), script_start_position,
-           ScriptSourceLocationType::kInternal, nullptr, nullptr,
-           kSharableCrossOrigin, kV8CacheOptionsDefault, ReferrerScriptInfo())
+           script_state, source_code, kSharableCrossOrigin,
+           kV8CacheOptionsDefault, ReferrerScriptInfo())
            .ToLocal(&script))
     return v8::MaybeLocal<v8::Value>();
 
diff --git a/third_party/WebKit/Source/bindings/core/v8/V8ScriptRunner.h b/third_party/WebKit/Source/bindings/core/v8/V8ScriptRunner.h
index cd0db2f..050fd171 100644
--- a/third_party/WebKit/Source/bindings/core/v8/V8ScriptRunner.h
+++ b/third_party/WebKit/Source/bindings/core/v8/V8ScriptRunner.h
@@ -51,7 +51,6 @@
 class CachedMetadataHandler;
 class ExecutionContext;
 class ScriptSourceCode;
-class ScriptStreamer;
 
 class CORE_EXPORT V8ScriptRunner final {
   STATIC_ONLY(V8ScriptRunner);
@@ -70,17 +69,6 @@
                                                   AccessControlStatus,
                                                   V8CacheOptions,
                                                   const ReferrerScriptInfo&);
-  static v8::MaybeLocal<v8::Script> CompileScript(ScriptState*,
-                                                  v8::Local<v8::String>,
-                                                  const String& file_name,
-                                                  const String& source_map_url,
-                                                  const TextPosition&,
-                                                  ScriptSourceLocationType,
-                                                  ScriptStreamer*,
-                                                  CachedMetadataHandler*,
-                                                  AccessControlStatus,
-                                                  V8CacheOptions,
-                                                  const ReferrerScriptInfo&);
   static v8::MaybeLocal<v8::Module> CompileModule(v8::Isolate*,
                                                   const String& source,
                                                   const String& file_name,
@@ -92,10 +80,8 @@
                                                      ExecutionContext*);
   static v8::MaybeLocal<v8::Value> CompileAndRunInternalScript(
       ScriptState*,
-      v8::Local<v8::String>,
-      v8::Isolate*,
-      const String& = String(),
-      const TextPosition& = TextPosition());
+      const ScriptSourceCode&,
+      v8::Isolate*);
   static v8::MaybeLocal<v8::Value> RunCompiledInternalScript(
       v8::Isolate*,
       v8::Local<v8::Script>);
diff --git a/third_party/WebKit/Source/bindings/core/v8/V8ScriptRunnerTest.cpp b/third_party/WebKit/Source/bindings/core/v8/V8ScriptRunnerTest.cpp
index 9c87c8f..4842baa 100644
--- a/third_party/WebKit/Source/bindings/core/v8/V8ScriptRunnerTest.cpp
+++ b/third_party/WebKit/Source/bindings/core/v8/V8ScriptRunnerTest.cpp
@@ -5,6 +5,7 @@
 #include "bindings/core/v8/V8ScriptRunner.h"
 
 #include "bindings/core/v8/ReferrerScriptInfo.h"
+#include "bindings/core/v8/ScriptSourceCode.h"
 #include "bindings/core/v8/V8BindingForCore.h"
 #include "bindings/core/v8/V8BindingForTesting.h"
 #include "core/loader/resource/ScriptResource.h"
@@ -27,14 +28,10 @@
 
   void SetUp() override {
     // To trick various layers of caching, increment a counter for each
-    // test and use it in code(), fielname() and url().
+    // test and use it in Code() and Url().
     counter_++;
   }
 
-  void TearDown() override {
-    resource_.Clear();
-  }
-
   WTF::String Code() const {
     // Simple function for testing. Note:
     // - Add counter to trick V8 code cache.
@@ -42,9 +39,6 @@
     return WTF::String::Format("a = function() { 1 + 1; } // %01000d\n",
                                counter_);
   }
-  WTF::String Filename() const {
-    return WTF::String::Format("whatever%d.js", counter_);
-  }
   KURL Url() const {
     return KURL(WTF::String::Format("http://bla.com/bla%d", counter_));
   }
@@ -58,29 +52,29 @@
     V8ScriptRunner::SetCacheTimeStamp(cache_handler);
   }
 
-  bool CompileScript(ScriptState* script_state, V8CacheOptions cache_options) {
-    return !V8ScriptRunner::CompileScript(
-                script_state, V8String(script_state->GetIsolate(), Code()),
-                Filename(), String(), WTF::TextPosition(),
-                ScriptSourceLocationType::kExternalFile, nullptr,
-                resource_.Get() ? resource_->CacheHandler() : nullptr,
-                kNotSharableCrossOrigin, cache_options, ReferrerScriptInfo())
+  bool CompileScript(ScriptState* script_state,
+                     const ScriptSourceCode& source_code,
+                     V8CacheOptions cache_options) {
+    return !V8ScriptRunner::CompileScript(script_state, source_code,
+                                          kNotSharableCrossOrigin,
+                                          cache_options, ReferrerScriptInfo())
                 .IsEmpty();
   }
 
-  void SetEmptyResource() {
-    resource_ = ScriptResource::CreateForTest(NullURL(), UTF8Encoding());
+  ScriptResource* CreateEmptyResource() {
+    return ScriptResource::CreateForTest(NullURL(), UTF8Encoding());
   }
 
-  void SetResource() {
-    resource_ = ScriptResource::CreateForTest(Url(), UTF8Encoding());
+  ScriptResource* CreateResource() {
+    ScriptResource* resource =
+        ScriptResource::CreateForTest(Url(), UTF8Encoding());
+    String code = Code();
+    resource->AppendData(code.Utf8().data(), code.Utf8().length());
+    resource->FinishForTest();
+    return resource;
   }
 
-  CachedMetadataHandler* CacheHandler() { return resource_->CacheHandler(); }
-
  protected:
-  Persistent<ScriptResource> resource_;
-
   static int counter_;
 };
 
@@ -88,46 +82,54 @@
 
 TEST_F(V8ScriptRunnerTest, resourcelessShouldPass) {
   V8TestingScope scope;
-  EXPECT_TRUE(CompileScript(scope.GetScriptState(), kV8CacheOptionsNone));
-  EXPECT_TRUE(CompileScript(scope.GetScriptState(), kV8CacheOptionsParse));
-  EXPECT_TRUE(CompileScript(scope.GetScriptState(), kV8CacheOptionsCode));
+  ScriptSourceCode source_code(Code(), ScriptSourceLocationType::kInternal,
+                               nullptr /* cache_handler */, Url());
+  EXPECT_TRUE(
+      CompileScript(scope.GetScriptState(), source_code, kV8CacheOptionsNone));
+  EXPECT_TRUE(
+      CompileScript(scope.GetScriptState(), source_code, kV8CacheOptionsParse));
+  EXPECT_TRUE(
+      CompileScript(scope.GetScriptState(), source_code, kV8CacheOptionsCode));
 }
 
 TEST_F(V8ScriptRunnerTest, emptyResourceDoesNotHaveCacheHandler) {
-  SetEmptyResource();
-  EXPECT_FALSE(CacheHandler());
+  Resource* resource = CreateEmptyResource();
+  EXPECT_FALSE(resource->CacheHandler());
 }
 
 TEST_F(V8ScriptRunnerTest, parseOption) {
   V8TestingScope scope;
-  SetResource();
-  EXPECT_TRUE(CompileScript(scope.GetScriptState(), kV8CacheOptionsParse));
+  ScriptSourceCode source_code(nullptr, CreateResource());
   EXPECT_TRUE(
-      CacheHandler()->GetCachedMetadata(TagForParserCache(CacheHandler())));
+      CompileScript(scope.GetScriptState(), source_code, kV8CacheOptionsParse));
+  CachedMetadataHandler* cache_handler = source_code.CacheHandler();
+  EXPECT_TRUE(
+      cache_handler->GetCachedMetadata(TagForParserCache(cache_handler)));
   EXPECT_FALSE(
-      CacheHandler()->GetCachedMetadata(TagForCodeCache(CacheHandler())));
+      cache_handler->GetCachedMetadata(TagForCodeCache(cache_handler)));
   // The cached data is associated with the encoding.
   ScriptResource* another_resource =
       ScriptResource::CreateForTest(Url(), UTF16LittleEndianEncoding());
-  EXPECT_FALSE(CacheHandler()->GetCachedMetadata(
+  EXPECT_FALSE(cache_handler->GetCachedMetadata(
       TagForParserCache(another_resource->CacheHandler())));
 }
 
 TEST_F(V8ScriptRunnerTest, codeOption) {
   V8TestingScope scope;
-  SetResource();
-  SetCacheTimeStamp(CacheHandler());
+  ScriptSourceCode source_code(nullptr, CreateResource());
+  CachedMetadataHandler* cache_handler = source_code.CacheHandler();
+  SetCacheTimeStamp(cache_handler);
 
-  EXPECT_TRUE(CompileScript(scope.GetScriptState(), kV8CacheOptionsCode));
+  EXPECT_TRUE(
+      CompileScript(scope.GetScriptState(), source_code, kV8CacheOptionsCode));
 
   EXPECT_FALSE(
-      CacheHandler()->GetCachedMetadata(TagForParserCache(CacheHandler())));
-  EXPECT_TRUE(
-      CacheHandler()->GetCachedMetadata(TagForCodeCache(CacheHandler())));
+      cache_handler->GetCachedMetadata(TagForParserCache(cache_handler)));
+  EXPECT_TRUE(cache_handler->GetCachedMetadata(TagForCodeCache(cache_handler)));
   // The cached data is associated with the encoding.
   ScriptResource* another_resource =
       ScriptResource::CreateForTest(Url(), UTF16LittleEndianEncoding());
-  EXPECT_FALSE(CacheHandler()->GetCachedMetadata(
+  EXPECT_FALSE(cache_handler->GetCachedMetadata(
       TagForCodeCache(another_resource->CacheHandler())));
 }
 
diff --git a/third_party/WebKit/Source/core/inspector/DevToolsHost.cpp b/third_party/WebKit/Source/core/inspector/DevToolsHost.cpp
index d35b0445..5dedf1d 100644
--- a/third_party/WebKit/Source/core/inspector/DevToolsHost.cpp
+++ b/third_party/WebKit/Source/core/inspector/DevToolsHost.cpp
@@ -29,6 +29,7 @@
 
 #include "core/inspector/DevToolsHost.h"
 
+#include "bindings/core/v8/ScriptSourceCode.h"
 #include "bindings/core/v8/V8BindingForCore.h"
 #include "bindings/core/v8/V8ScriptRunner.h"
 #include "core/clipboard/Pasteboard.h"
@@ -137,11 +138,10 @@
       Frame::NotifyUserActivation(frontend_frame_);
   v8::MicrotasksScope microtasks(script_state->GetIsolate(),
                                  v8::MicrotasksScope::kRunMicrotasks);
-  v8::Local<v8::String> source =
-      V8AtomicString(script_state->GetIsolate(), expression.Utf8().data());
-  V8ScriptRunner::CompileAndRunInternalScript(script_state, source,
-                                              script_state->GetIsolate(),
-                                              String(), TextPosition());
+  ScriptSourceCode source_code(expression, ScriptSourceLocationType::kInternal,
+                               nullptr, KURL(), TextPosition());
+  V8ScriptRunner::CompileAndRunInternalScript(script_state, source_code,
+                                              script_state->GetIsolate());
 }
 
 void DevToolsHost::DisconnectClient() {
diff --git a/third_party/WebKit/Source/core/inspector/ThreadDebugger.cpp b/third_party/WebKit/Source/core/inspector/ThreadDebugger.cpp
index 918681f..32306ce5 100644
--- a/third_party/WebKit/Source/core/inspector/ThreadDebugger.cpp
+++ b/third_party/WebKit/Source/core/inspector/ThreadDebugger.cpp
@@ -5,6 +5,7 @@
 #include "core/inspector/ThreadDebugger.h"
 
 #include <memory>
+#include "bindings/core/v8/ScriptSourceCode.h"
 #include "bindings/core/v8/SourceLocation.h"
 #include "bindings/core/v8/V8BindingForCore.h"
 #include "bindings/core/v8/V8Blob.h"
@@ -278,8 +279,9 @@
   bool success =
       V8ScriptRunner::CompileAndRunInternalScript(
           ScriptState::From(context),
-
-          V8String(isolate_, "(function(e) { console.log(e.type, e); })"),
+          ScriptSourceCode("(function(e) { console.log(e.type, e); })",
+                           ScriptSourceLocationType::kInternal, nullptr, KURL(),
+                           TextPosition()),
           isolate_)
           .ToLocal(&function_value) &&
       function_value->IsFunction();
diff --git a/third_party/WebKit/Source/core/workers/DedicatedWorkerMessagingProxy.cpp b/third_party/WebKit/Source/core/workers/DedicatedWorkerMessagingProxy.cpp
index 9d5d83d22..a796386 100644
--- a/third_party/WebKit/Source/core/workers/DedicatedWorkerMessagingProxy.cpp
+++ b/third_party/WebKit/Source/core/workers/DedicatedWorkerMessagingProxy.cpp
@@ -114,6 +114,9 @@
         ->GetTaskRunner(TaskType::kPostedMessage)
         ->PostTask(BLINK_FROM_HERE, std::move(task));
   } else {
+    // GetWorkerThread() returns nullptr while the worker thread is being
+    // created. In that case, push events into the queue and dispatch them in
+    // WorkerThreadCreated().
     queued_early_tasks_.push_back(
         QueuedTask{std::move(message), std::move(channels), stack_id});
   }
@@ -166,17 +169,25 @@
   if (!worker_object_)
     return;
 
-  // We don't bother checking the askedToTerminate() flag here, because
-  // exceptions should *always* be reported even if the thread is terminated.
-  // This is intentionally different than the behavior in MessageWorkerTask,
-  // because terminated workers no longer deliver messages (section 4.6 of the
-  // WebWorker spec), but they do report exceptions.
-
+  // We don't bother checking the AskedToTerminate() flag for dispatching the
+  // event on the owner context, because exceptions should *always* be reported
+  // even if the thread is terminated as the spec says:
+  //
+  // "Thus, error reports propagate up to the chain of dedicated workers up to
+  // the original Document, even if some of the workers along this chain have
+  // been terminated and garbage collected."
+  // https://html.spec.whatwg.org/multipage/workers.html#runtime-script-errors-2
   ErrorEvent* event =
       ErrorEvent::Create(error_message, location->Clone(), nullptr);
   if (worker_object_->DispatchEvent(event) != DispatchEventResult::kNotCanceled)
     return;
 
+  // The worker thread can already be terminated.
+  if (!GetWorkerThread()) {
+    DCHECK(AskedToTerminate());
+    return;
+  }
+
   // The HTML spec requires to queue an error event using the DOM manipulation
   // task source.
   // https://html.spec.whatwg.org/multipage/workers.html#runtime-script-errors-2
diff --git a/third_party/WebKit/Source/core/workers/ThreadedMessagingProxyBase.h b/third_party/WebKit/Source/core/workers/ThreadedMessagingProxyBase.h
index 1ffff1ef..e32e4737 100644
--- a/third_party/WebKit/Source/core/workers/ThreadedMessagingProxyBase.h
+++ b/third_party/WebKit/Source/core/workers/ThreadedMessagingProxyBase.h
@@ -85,6 +85,8 @@
   ExecutionContext* GetExecutionContext() const;
   ParentFrameTaskRunners* GetParentFrameTaskRunners() const;
   WorkerInspectorProxy* GetWorkerInspectorProxy() const;
+
+  // May return nullptr after termination is requested.
   WorkerThread* GetWorkerThread() const;
 
   bool AskedToTerminate() const { return asked_to_terminate_; }
diff --git a/third_party/WebKit/Source/modules/accessibility/AXObjectCacheImpl.cpp b/third_party/WebKit/Source/modules/accessibility/AXObjectCacheImpl.cpp
index 73ff2f2..215b275 100644
--- a/third_party/WebKit/Source/modules/accessibility/AXObjectCacheImpl.cpp
+++ b/third_party/WebKit/Source/modules/accessibility/AXObjectCacheImpl.cpp
@@ -1247,7 +1247,6 @@
   permission_service_->AddPermissionObserver(
       CreatePermissionDescriptor(
           mojom::blink::PermissionName::ACCESSIBILITY_EVENTS),
-      document_->GetExecutionContext()->GetSecurityOrigin(),
       accessibility_event_permission_, std::move(observer));
 }
 
@@ -1270,7 +1269,6 @@
   permission_service_->RequestPermission(
       CreatePermissionDescriptor(
           mojom::blink::PermissionName::ACCESSIBILITY_EVENTS),
-      document_->GetExecutionContext()->GetSecurityOrigin(),
       Frame::HasTransientUserActivation(document_->GetFrame()),
       WTF::Bind(&AXObjectCacheImpl::OnPermissionStatusChange,
                 WrapPersistent(this)));
diff --git a/third_party/WebKit/Source/modules/budget/BudgetService.cpp b/third_party/WebKit/Source/modules/budget/BudgetService.cpp
index 4b0539c..7454c665 100644
--- a/third_party/WebKit/Source/modules/budget/BudgetService.cpp
+++ b/third_party/WebKit/Source/modules/budget/BudgetService.cpp
@@ -95,10 +95,7 @@
   ScriptPromise promise = resolver->Promise();
 
   // Get the budget from the browser BudgetService.
-  scoped_refptr<const SecurityOrigin> origin(
-      ExecutionContext::From(script_state)->GetSecurityOrigin());
-  service_->GetBudget(origin,
-                      WTF::Bind(&BudgetService::GotBudget, WrapPersistent(this),
+  service_->GetBudget(WTF::Bind(&BudgetService::GotBudget, WrapPersistent(this),
                                 WrapPersistent(resolver)));
   return promise;
 }
@@ -142,11 +139,9 @@
   ScriptPromise promise = resolver->Promise();
 
   // Call to the BudgetService to place the reservation.
-  scoped_refptr<const SecurityOrigin> origin(
-      ExecutionContext::From(script_state)->GetSecurityOrigin());
-  service_->Reserve(origin, type,
-                    WTF::Bind(&BudgetService::GotReservation,
-                              WrapPersistent(this), WrapPersistent(resolver)));
+  service_->Reserve(
+      type, WTF::Bind(&BudgetService::GotReservation, WrapPersistent(this),
+                      WrapPersistent(resolver)));
   return promise;
 }
 
diff --git a/third_party/WebKit/Source/modules/notifications/NotificationManager.cpp b/third_party/WebKit/Source/modules/notifications/NotificationManager.cpp
index 7bc802f..962d417 100644
--- a/third_party/WebKit/Source/modules/notifications/NotificationManager.cpp
+++ b/third_party/WebKit/Source/modules/notifications/NotificationManager.cpp
@@ -80,7 +80,6 @@
   Document* doc = ToDocumentOrNull(context);
   permission_service_->RequestPermission(
       CreatePermissionDescriptor(mojom::blink::PermissionName::NOTIFICATIONS),
-      context->GetSecurityOrigin(),
       Frame::HasTransientUserActivation(doc ? doc->GetFrame() : nullptr),
       WTF::Bind(&NotificationManager::OnPermissionRequestComplete,
                 WrapPersistent(this), WrapPersistent(resolver),
diff --git a/third_party/WebKit/Source/modules/permissions/PermissionStatus.cpp b/third_party/WebKit/Source/modules/permissions/PermissionStatus.cpp
index de7fb2a..00243d58 100644
--- a/third_party/WebKit/Source/modules/permissions/PermissionStatus.cpp
+++ b/third_party/WebKit/Source/modules/permissions/PermissionStatus.cpp
@@ -93,9 +93,8 @@
   mojom::blink::PermissionServicePtr service;
   ConnectToPermissionService(GetExecutionContext(),
                              mojo::MakeRequest(&service));
-  service->AddPermissionObserver(descriptor_->Clone(),
-                                 GetExecutionContext()->GetSecurityOrigin(),
-                                 status_, std::move(observer));
+  service->AddPermissionObserver(descriptor_->Clone(), status_,
+                                 std::move(observer));
 }
 
 void PermissionStatus::StopListening() {
diff --git a/third_party/WebKit/Source/modules/permissions/Permissions.cpp b/third_party/WebKit/Source/modules/permissions/Permissions.cpp
index 2b1c534..ceb0e41a 100644
--- a/third_party/WebKit/Source/modules/permissions/Permissions.cpp
+++ b/third_party/WebKit/Source/modules/permissions/Permissions.cpp
@@ -171,7 +171,6 @@
   PermissionDescriptorPtr descriptor_copy = descriptor->Clone();
   GetService(ExecutionContext::From(script_state))
       .HasPermission(std::move(descriptor),
-                     ExecutionContext::From(script_state)->GetSecurityOrigin(),
                      WTF::Bind(&Permissions::TaskComplete, WrapPersistent(this),
                                WrapPersistent(resolver),
                                WTF::Passed(std::move(descriptor_copy))));
@@ -198,7 +197,7 @@
   Frame* frame = doc ? doc->GetFrame() : nullptr;
   GetService(ExecutionContext::From(script_state))
       .RequestPermission(
-          std::move(descriptor), context->GetSecurityOrigin(),
+          std::move(descriptor),
           Frame::HasTransientUserActivation(frame,
                                             true /* checkIfMainThread */),
           WTF::Bind(&Permissions::TaskComplete, WrapPersistent(this),
@@ -224,7 +223,6 @@
   GetService(ExecutionContext::From(script_state))
       .RevokePermission(
           std::move(descriptor),
-          ExecutionContext::From(script_state)->GetSecurityOrigin(),
           WTF::Bind(&Permissions::TaskComplete, WrapPersistent(this),
                     WrapPersistent(resolver),
                     WTF::Passed(std::move(descriptor_copy))));
@@ -277,7 +275,7 @@
   Frame* frame = doc ? doc->GetFrame() : nullptr;
   GetService(ExecutionContext::From(script_state))
       .RequestPermissions(
-          std::move(internal_permissions), context->GetSecurityOrigin(),
+          std::move(internal_permissions),
           Frame::HasTransientUserActivation(frame,
                                             true /* checkIfMainThread */),
           WTF::Bind(&Permissions::BatchTaskComplete, WrapPersistent(this),
diff --git a/third_party/WebKit/Source/modules/quota/StorageManager.cpp b/third_party/WebKit/Source/modules/quota/StorageManager.cpp
index 885a28c9..d663ab1 100644
--- a/third_party/WebKit/Source/modules/quota/StorageManager.cpp
+++ b/third_party/WebKit/Source/modules/quota/StorageManager.cpp
@@ -82,7 +82,6 @@
   GetPermissionService(ExecutionContext::From(script_state))
       .RequestPermission(
           CreatePermissionDescriptor(PermissionName::DURABLE_STORAGE),
-          ExecutionContext::From(script_state)->GetSecurityOrigin(),
           Frame::HasTransientUserActivation(doc ? doc->GetFrame() : nullptr),
           WTF::Bind(&StorageManager::PermissionRequestComplete,
                     WrapPersistent(this), WrapPersistent(resolver)));
@@ -106,7 +105,6 @@
   GetPermissionService(ExecutionContext::From(script_state))
       .HasPermission(
           CreatePermissionDescriptor(PermissionName::DURABLE_STORAGE),
-          ExecutionContext::From(script_state)->GetSecurityOrigin(),
           WTF::Bind(&StorageManager::PermissionRequestComplete,
                     WrapPersistent(this), WrapPersistent(resolver)));
   return promise;
diff --git a/third_party/WebKit/Source/modules/webmidi/MIDIAccessInitializer.cpp b/third_party/WebKit/Source/modules/webmidi/MIDIAccessInitializer.cpp
index 58e9df7..d401dce 100644
--- a/third_party/WebKit/Source/modules/webmidi/MIDIAccessInitializer.cpp
+++ b/third_party/WebKit/Source/modules/webmidi/MIDIAccessInitializer.cpp
@@ -44,7 +44,6 @@
   Document* doc = ToDocumentOrNull(GetExecutionContext());
   permission_service_->RequestPermission(
       CreateMidiPermissionDescriptor(options_.hasSysex() && options_.sysex()),
-      GetExecutionContext()->GetSecurityOrigin(),
       Frame::HasTransientUserActivation(doc ? doc->GetFrame() : nullptr),
       WTF::Bind(&MIDIAccessInitializer::OnPermissionsUpdated,
                 WrapPersistent(this)));
diff --git a/third_party/WebKit/public/platform/modules/budget_service/budget_service.mojom b/third_party/WebKit/public/platform/modules/budget_service/budget_service.mojom
index c84953b..8633f1e 100644
--- a/third_party/WebKit/public/platform/modules/budget_service/budget_service.mojom
+++ b/third_party/WebKit/public/platform/modules/budget_service/budget_service.mojom
@@ -4,8 +4,6 @@
 
 module blink.mojom;
 
-import "url/mojo/origin.mojom";
-
 enum BudgetOperationType {
   SILENT_PUSH,
   INVALID_OPERATION
@@ -34,7 +32,8 @@
 // for the budget available for an origin.
 interface BudgetService {
   GetCost(BudgetOperationType operation) => (double cost);
-  GetBudget(url.mojom.Origin origin) => (BudgetServiceErrorType error_type, array<BudgetState> budget);
-  Reserve(url.mojom.Origin origin, BudgetOperationType operation) => (BudgetServiceErrorType error_type, bool success);
+  GetBudget() => (BudgetServiceErrorType error_type, array<BudgetState> budget);
+  Reserve(BudgetOperationType operation)
+      => (BudgetServiceErrorType error_type, bool success);
 };
 
diff --git a/third_party/WebKit/public/platform/modules/permissions/permission.mojom b/third_party/WebKit/public/platform/modules/permissions/permission.mojom
index bf271f3..88b2758 100644
--- a/third_party/WebKit/public/platform/modules/permissions/permission.mojom
+++ b/third_party/WebKit/public/platform/modules/permissions/permission.mojom
@@ -5,7 +5,6 @@
 module blink.mojom;
 
 import "third_party/WebKit/public/platform/modules/permissions/permission_status.mojom";
-import "url/mojo/origin.mojom";
 
 enum PermissionName {
   GEOLOCATION,
@@ -52,20 +51,16 @@
 // methods to check, request, and revoke permissions. It also allows a client to
 // start listening to permission changes.
 interface PermissionService {
-  HasPermission(PermissionDescriptor permission, url.mojom.Origin origin)
-    => (PermissionStatus status);
-  RequestPermission(PermissionDescriptor permission, url.mojom.Origin origin,
-      bool user_gesture)
-    => (PermissionStatus status);
-  RequestPermissions(array<PermissionDescriptor> permission, url.mojom.Origin origin,
-      bool user_gesture)
-    => (array<PermissionStatus> statuses);
-  RevokePermission(PermissionDescriptor permission, url.mojom.Origin origin)
-    => (PermissionStatus status);
-  // Subscribes |observer| to updates about changes to |origin|'s access to
-  // |permission|. Closing the pipe will cancel the subscription.
+  HasPermission(PermissionDescriptor permission) => (PermissionStatus status);
+  RequestPermission(PermissionDescriptor permission, bool user_gesture)
+      => (PermissionStatus status);
+  RequestPermissions(array<PermissionDescriptor> permission, bool user_gesture)
+      => (array<PermissionStatus> statuses);
+  RevokePermission(PermissionDescriptor permission)
+      => (PermissionStatus status);
+  // Subscribes |observer| to updates about changes to the current origin's
+  // access to |permission|. Closing the pipe will cancel the subscription.
   AddPermissionObserver(PermissionDescriptor permission,
-                        url.mojom.Origin origin,
                         PermissionStatus last_known_status,
                         PermissionObserver observer);
 };
diff --git a/ui/events/blink/input_scroll_elasticity_controller.cc b/ui/events/blink/input_scroll_elasticity_controller.cc
index 41fe35c..b5c753a 100644
--- a/ui/events/blink/input_scroll_elasticity_controller.cc
+++ b/ui/events/blink/input_scroll_elasticity_controller.cc
@@ -93,8 +93,8 @@
     : helper_(helper),
       state_(kStateInactive),
       momentum_animation_reset_at_next_frame_(false),
-      weak_factory_(this) {
-}
+      received_overscroll_update_(false),
+      weak_factory_(this) {}
 
 InputScrollElasticityController::~InputScrollElasticityController() {
 }
@@ -115,6 +115,8 @@
 
   switch (gesture_event.GetType()) {
     case blink::WebInputEvent::kGestureScrollBegin: {
+      received_overscroll_update_ = false;
+      overscroll_behavior_ = cc::OverscrollBehavior();
       if (gesture_event.data.scroll_begin.synthetic)
         return;
       if (gesture_event.data.scroll_begin.inertial_phase ==
@@ -141,6 +143,11 @@
           break;
         case kStateActiveScroll:
         case kStateMomentumScroll:
+          if (!received_overscroll_update_ &&
+              !scroll_result.unused_scroll_delta.IsZero()) {
+            overscroll_behavior_ = scroll_result.overscroll_behavior;
+            received_overscroll_update_ = true;
+          }
           UpdateVelocity(event_delta, event_timestamp);
           Overscroll(event_delta, scroll_result.unused_scroll_delta);
           if (gesture_event.data.scroll_update.inertial_phase ==
@@ -212,9 +219,17 @@
   // Don't allow overscrolling in a direction where scrolling is possible.
   if (!PinnedHorizontally(adjusted_overscroll_delta.x()))
     adjusted_overscroll_delta.set_x(0);
-  if (!PinnedVertically(adjusted_overscroll_delta.y())) {
+  if (!PinnedVertically(adjusted_overscroll_delta.y()))
     adjusted_overscroll_delta.set_y(0);
-  }
+
+  // Don't allow overscrolling in a direction that has
+  // OverscrollBehaviorTypeNone.
+  if (overscroll_behavior_.x ==
+      cc::OverscrollBehavior::kOverscrollBehaviorTypeNone)
+    adjusted_overscroll_delta.set_x(0);
+  if (overscroll_behavior_.y ==
+      cc::OverscrollBehavior::kOverscrollBehaviorTypeNone)
+    adjusted_overscroll_delta.set_y(0);
 
   // Require a minimum of 10 units of overscroll before starting the rubber-band
   // stretch effect, so that small stray motions don't trigger it. If that
diff --git a/ui/events/blink/input_scroll_elasticity_controller.h b/ui/events/blink/input_scroll_elasticity_controller.h
index 4e44584b..6c08305 100644
--- a/ui/events/blink/input_scroll_elasticity_controller.h
+++ b/ui/events/blink/input_scroll_elasticity_controller.h
@@ -7,6 +7,7 @@
 
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
+#include "cc/input/overscroll_behavior.h"
 #include "cc/input/scroll_elasticity_helper.h"
 #include "third_party/WebKit/public/platform/WebGestureEvent.h"
 #include "third_party/WebKit/public/platform/WebInputEvent.h"
@@ -140,6 +141,9 @@
   // behavior as would happen if the scroll were caused by an active scroll).
   bool momentum_animation_reset_at_next_frame_;
 
+  bool received_overscroll_update_;
+  cc::OverscrollBehavior overscroll_behavior_;
+
   base::WeakPtrFactory<InputScrollElasticityController> weak_factory_;
   DISALLOW_COPY_AND_ASSIGN(InputScrollElasticityController);
 };
diff --git a/ui/events/blink/input_scroll_elasticity_controller_unittest.cc b/ui/events/blink/input_scroll_elasticity_controller_unittest.cc
index df552c39..777b5c93 100644
--- a/ui/events/blink/input_scroll_elasticity_controller_unittest.cc
+++ b/ui/events/blink/input_scroll_elasticity_controller_unittest.cc
@@ -106,7 +106,9 @@
   void SendGestureScrollUpdate(
       InertialPhaseState inertialPhase,
       const gfx::Vector2dF& event_delta = gfx::Vector2dF(),
-      const gfx::Vector2dF& overscroll_delta = gfx::Vector2dF()) {
+      const gfx::Vector2dF& overscroll_delta = gfx::Vector2dF(),
+      const cc::OverscrollBehavior& overscroll_behavior =
+          cc::OverscrollBehavior()) {
     TickCurrentTime();
     blink::WebGestureEvent event(
         blink::WebInputEvent::kGestureScrollUpdate,
@@ -121,6 +123,7 @@
     cc::InputHandlerScrollResult scroll_result;
     scroll_result.did_overscroll_root = !overscroll_delta.IsZero();
     scroll_result.unused_scroll_delta = overscroll_delta;
+    scroll_result.overscroll_behavior = overscroll_behavior;
 
     controller_.ObserveGestureEventAndResult(event, scroll_result);
     input_event_count_ += 1;
@@ -424,5 +427,76 @@
   EXPECT_GT(ticks_to_zero, 3);
 }
 
+// Verify that OverscrollBehaviorTypeNone disables the stretching on the
+// specified axis.
+TEST_F(ScrollElasticityControllerTest, OverscrollBehavior) {
+  helper_.SetScrollOffsetAndMaxScrollOffset(gfx::ScrollOffset(0, 0),
+                                            gfx::ScrollOffset(0, 0));
+
+  // If we set OverscrollBehaviorTypeNone on x, we should not see a stretch
+  // in the X direction.
+  SendGestureScrollBegin(NonMomentumPhase);
+  SendGestureScrollUpdate(
+      NonMomentumPhase, gfx::Vector2dF(10, 0), gfx::Vector2dF(10, 0),
+      cc::OverscrollBehavior(
+          cc::OverscrollBehavior::kOverscrollBehaviorTypeNone,
+          cc::OverscrollBehavior::kOverscrollBehaviorTypeAuto));
+  EXPECT_EQ(0, helper_.set_stretch_amount_count());
+  EXPECT_EQ(0.f, helper_.StretchAmount().x());
+  EXPECT_EQ(0.f, helper_.StretchAmount().y());
+  helper_.SetStretchAmount(gfx::Vector2dF());
+  EXPECT_EQ(1, helper_.set_stretch_amount_count());
+  SendGestureScrollEnd();
+  EXPECT_EQ(0, helper_.request_begin_frame_count());
+
+  // If we set OverscrollBehaviorTypeNone on x, we could still see a stretch
+  // in the Y direction
+  SendGestureScrollBegin(NonMomentumPhase);
+  SendGestureScrollUpdate(
+      NonMomentumPhase, gfx::Vector2dF(0, 10), gfx::Vector2dF(0, 10),
+      cc::OverscrollBehavior(
+          cc::OverscrollBehavior::kOverscrollBehaviorTypeNone,
+          cc::OverscrollBehavior::kOverscrollBehaviorTypeAuto));
+  EXPECT_EQ(2, helper_.set_stretch_amount_count());
+  EXPECT_EQ(0.f, helper_.StretchAmount().x());
+  EXPECT_LT(0.f, helper_.StretchAmount().y());
+  helper_.SetStretchAmount(gfx::Vector2dF());
+  EXPECT_EQ(3, helper_.set_stretch_amount_count());
+  SendGestureScrollEnd();
+  EXPECT_EQ(0, helper_.request_begin_frame_count());
+
+  // If we set OverscrollBehaviorTypeNone on y, we should not see a stretch
+  // in the Y direction.
+  SendGestureScrollBegin(NonMomentumPhase);
+  SendGestureScrollUpdate(
+      NonMomentumPhase, gfx::Vector2dF(0, 10), gfx::Vector2dF(0, 10),
+      cc::OverscrollBehavior(
+          cc::OverscrollBehavior::kOverscrollBehaviorTypeAuto,
+          cc::OverscrollBehavior::kOverscrollBehaviorTypeNone));
+  EXPECT_EQ(3, helper_.set_stretch_amount_count());
+  EXPECT_EQ(0.f, helper_.StretchAmount().x());
+  EXPECT_EQ(0.f, helper_.StretchAmount().y());
+  helper_.SetStretchAmount(gfx::Vector2dF());
+  EXPECT_EQ(4, helper_.set_stretch_amount_count());
+  SendGestureScrollEnd();
+  EXPECT_EQ(0, helper_.request_begin_frame_count());
+
+  // If we set OverscrollBehaviorTypeNone on y, we could still see a stretch
+  // in the X direction.
+  SendGestureScrollBegin(NonMomentumPhase);
+  SendGestureScrollUpdate(
+      NonMomentumPhase, gfx::Vector2dF(10, 0), gfx::Vector2dF(10, 0),
+      cc::OverscrollBehavior(
+          cc::OverscrollBehavior::kOverscrollBehaviorTypeAuto,
+          cc::OverscrollBehavior::kOverscrollBehaviorTypeNone));
+  EXPECT_EQ(5, helper_.set_stretch_amount_count());
+  EXPECT_LT(0.f, helper_.StretchAmount().x());
+  EXPECT_EQ(0.f, helper_.StretchAmount().y());
+  helper_.SetStretchAmount(gfx::Vector2dF());
+  EXPECT_EQ(6, helper_.set_stretch_amount_count());
+  SendGestureScrollEnd();
+  EXPECT_EQ(0, helper_.request_begin_frame_count());
+}
+
 }  // namespace
 }  // namespace ui