diff --git a/DEPS b/DEPS
index 7d66e721e..9c227e5e 100644
--- a/DEPS
+++ b/DEPS
@@ -40,7 +40,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling Skia
   # and whatever else without interference from each other.
-  'skia_revision': 'e6c210ae01137b283ba7c55b3b197771f425eb74',
+  'skia_revision': '967c84a747ff0d942a35895fa75969db55ca9832',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
@@ -64,7 +64,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling PDFium
   # and whatever else without interference from each other.
-  'pdfium_revision': 'dbc3d3e1e0b28692c31f08f6b4c606577255078d',
+  'pdfium_revision': '3c58aa0bf51c64eb126be165e7478e70fbb68043',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling openmax_dl
   # and whatever else without interference from each other.
diff --git a/ash/display/window_tree_host_manager.cc b/ash/display/window_tree_host_manager.cc
index 358804a..b562c761 100644
--- a/ash/display/window_tree_host_manager.cc
+++ b/ash/display/window_tree_host_manager.cc
@@ -328,6 +328,10 @@
 }
 
 aura::Window* WindowTreeHostManager::GetPrimaryRootWindow() {
+  // If |primary_tree_host_for_replace_| is set, it means |primary_display_id|
+  // is kInvalidDisplayId.
+  if (primary_tree_host_for_replace_)
+    return GetWindow(primary_tree_host_for_replace_);
   return GetRootWindowForDisplayId(primary_display_id);
 }
 
@@ -633,6 +637,8 @@
   // Delete most of root window related objects, but don't delete
   // root window itself yet because the stack may be using it.
   controller->Shutdown();
+  if (primary_tree_host_for_replace_ == host_to_delete)
+    primary_tree_host_for_replace_ = nullptr;
   base::ThreadTaskRunnerHandle::Get()->DeleteSoon(FROM_HERE, controller);
 }
 
diff --git a/ash/mus/bridge/shell_port_mash.cc b/ash/mus/bridge/shell_port_mash.cc
index 5abe4f6..da1cd51 100644
--- a/ash/mus/bridge/shell_port_mash.cc
+++ b/ash/mus/bridge/shell_port_mash.cc
@@ -49,6 +49,7 @@
 #include "ash/wm/window_resizer.h"
 #include "ash/wm/window_util.h"
 #include "ash/wm/workspace/workspace_event_handler_aura.h"
+#include "ash/wm_display_observer.h"
 #include "ash/wm_window.h"
 #include "base/command_line.h"
 #include "base/memory/ptr_util.h"
@@ -159,6 +160,9 @@
 }
 
 void ShellPortMash::Shutdown() {
+  if (added_display_observer_)
+    Shell::Get()->window_tree_host_manager()->RemoveObserver(this);
+
   if (mus_state_)
     mus_state_->pointer_watcher_adapter.reset();
 
@@ -200,6 +204,10 @@
 
 const display::ManagedDisplayInfo& ShellPortMash::GetDisplayInfo(
     int64_t display_id) const {
+  // TODO(sky): mash should use this too http://crbug.com/718860.
+  if (GetAshConfig() == Config::MUS)
+    return Shell::Get()->display_manager()->GetDisplayInfo(display_id);
+
   // TODO(mash): implement http://crbug.com/622480.
   NOTIMPLEMENTED();
   static display::ManagedDisplayInfo fake_info;
@@ -207,24 +215,47 @@
 }
 
 bool ShellPortMash::IsActiveDisplayId(int64_t display_id) const {
+  // TODO(sky): mash should use this too http://crbug.com/718860.
+  if (GetAshConfig() == Config::MUS)
+    return Shell::Get()->display_manager()->IsActiveDisplayId(display_id);
+
   // TODO(mash): implement http://crbug.com/622480.
   NOTIMPLEMENTED();
   return true;
 }
 
 display::Display ShellPortMash::GetFirstDisplay() const {
+  // TODO(sky): mash should use this too http://crbug.com/718860.
+  if (GetAshConfig() == Config::MUS) {
+    return Shell::Get()
+        ->display_manager()
+        ->software_mirroring_display_list()[0];
+  }
+
   // TODO(mash): implement http://crbug.com/622480.
   NOTIMPLEMENTED();
   return display::Screen::GetScreen()->GetPrimaryDisplay();
 }
 
 bool ShellPortMash::IsInUnifiedMode() const {
+  // TODO(sky): mash should use this too http://crbug.com/718860.
+  if (GetAshConfig() == Config::MUS)
+    return Shell::Get()->display_manager()->IsInUnifiedMode();
+
   // TODO(mash): implement http://crbug.com/622480.
   NOTIMPLEMENTED();
   return false;
 }
 
 bool ShellPortMash::IsInUnifiedModeIgnoreMirroring() const {
+  // TODO(sky): mash should use this too http://crbug.com/718860.
+  if (GetAshConfig() == Config::MUS) {
+    return Shell::Get()
+               ->display_manager()
+               ->current_default_multi_display_mode() ==
+           display::DisplayManager::UNIFIED;
+  }
+
   // TODO(mash): implement http://crbug.com/622480.
   NOTIMPLEMENTED();
   return false;
@@ -387,13 +418,27 @@
 }
 
 void ShellPortMash::AddDisplayObserver(WmDisplayObserver* observer) {
-  // TODO: need WmDisplayObserver support for mus. http://crbug.com/705831.
-  NOTIMPLEMENTED();
+  // TODO(sky): mash should use the same code as mus/classic and
+  // WmDisplayObserver should be removed; http://crbug.com/718860.
+  if (GetAshConfig() == Config::MASH) {
+    NOTIMPLEMENTED();
+    return;
+  }
+  if (!added_display_observer_) {
+    added_display_observer_ = true;
+    Shell::Get()->window_tree_host_manager()->AddObserver(this);
+  }
+  display_observers_.AddObserver(observer);
 }
 
 void ShellPortMash::RemoveDisplayObserver(WmDisplayObserver* observer) {
-  // TODO: need WmDisplayObserver support for mus. http://crbug.com/705831.
-  NOTIMPLEMENTED();
+  // TODO(sky): mash should use the same code as mus/classic and
+  // WmDisplayObserver should be removed; http://crbug.com/718860.
+  if (GetAshConfig() == Config::MASH) {
+    NOTIMPLEMENTED();
+    return;
+  }
+  display_observers_.RemoveObserver(observer);
 }
 
 void ShellPortMash::AddPointerWatcher(views::PointerWatcher* watcher,
@@ -570,5 +615,15 @@
       mash_state_->accelerator_controller_registrar.get());
 }
 
+void ShellPortMash::OnDisplayConfigurationChanging() {
+  for (auto& observer : display_observers_)
+    observer.OnDisplayConfigurationChanging();
+}
+
+void ShellPortMash::OnDisplayConfigurationChanged() {
+  for (auto& observer : display_observers_)
+    observer.OnDisplayConfigurationChanged();
+}
+
 }  // namespace mus
 }  // namespace ash
diff --git a/ash/mus/bridge/shell_port_mash.h b/ash/mus/bridge/shell_port_mash.h
index 2456370..4d409648 100644
--- a/ash/mus/bridge/shell_port_mash.h
+++ b/ash/mus/bridge/shell_port_mash.h
@@ -10,6 +10,7 @@
 #include <memory>
 #include <vector>
 
+#include "ash/display/window_tree_host_manager.h"
 #include "ash/shell_port.h"
 #include "base/macros.h"
 
@@ -36,7 +37,7 @@
 class ShellPortMashTestApi;
 
 // ShellPort implementation for mash/mus. See ash/README.md for more.
-class ShellPortMash : public ShellPort {
+class ShellPortMash : public ShellPort, public WindowTreeHostManager::Observer {
  public:
   // If |create_session_state_delegate_stub| is true SessionStateDelegateStub is
   // created. If false, the SessionStateDelegate from Shell is used.
@@ -138,6 +139,10 @@
         accelerator_controller_delegate;
   };
 
+  // WindowTreeHostManager::Observer:
+  void OnDisplayConfigurationChanging() override;
+  void OnDisplayConfigurationChanged() override;
+
   WindowManager* window_manager_;
 
   // TODO(sky): remove this once mash supports simple display management.
@@ -150,6 +155,9 @@
 
   std::unique_ptr<SessionStateDelegate> session_state_delegate_;
 
+  bool added_display_observer_ = false;
+  base::ObserverList<WmDisplayObserver> display_observers_;
+
   DISALLOW_COPY_AND_ASSIGN(ShellPortMash);
 };
 
diff --git a/ash/system/screen_layout_observer.cc b/ash/system/screen_layout_observer.cc
index 1614ca8..bef63f62 100644
--- a/ash/system/screen_layout_observer.cc
+++ b/ash/system/screen_layout_observer.cc
@@ -370,7 +370,7 @@
   else
     current_display_mode_ = DisplayMode::SINGLE;
 
-  if (!show_notifications_for_testing)
+  if (!show_notifications_for_testing_)
     return;
 
   base::string16 message;
diff --git a/ash/system/screen_layout_observer.h b/ash/system/screen_layout_observer.h
index d103bc62..eb3a21e 100644
--- a/ash/system/screen_layout_observer.h
+++ b/ash/system/screen_layout_observer.h
@@ -30,7 +30,7 @@
   // Notifications are shown in production and are not shown in unit tests.
   // Allow individual unit tests to show notifications.
   void set_show_notifications_for_testing(bool show) {
-    show_notifications_for_testing = show;
+    show_notifications_for_testing_ = show;
   }
 
  private:
@@ -77,7 +77,7 @@
   DisplayMode old_display_mode_ = DisplayMode::SINGLE;
   DisplayMode current_display_mode_ = DisplayMode::SINGLE;
 
-  bool show_notifications_for_testing = true;
+  bool show_notifications_for_testing_ = true;
 
   DISALLOW_COPY_AND_ASSIGN(ScreenLayoutObserver);
 };
diff --git a/ash/test/ash_test_helper.cc b/ash/test/ash_test_helper.cc
index d6911f5..6d7286b 100644
--- a/ash/test/ash_test_helper.cc
+++ b/ash/test/ash_test_helper.cc
@@ -178,20 +178,21 @@
   if (start_session)
     session_controller_client_->CreatePredefinedUserSessions(1);
 
-  if (config_ == Config::CLASSIC) {
-    // ScreenLayoutObserver is specific to classic-ash.
+  // TODO(sky): mash should use this too http://crbug.com/718860.
+  if (config_ != Config::MASH) {
     // Tests that change the display configuration generally don't care about
     // the notifications and the popup UI can interfere with things like
     // cursors.
     shell->screen_layout_observer()->set_show_notifications_for_testing(false);
 
-    // DisplayManager is specific to classic-ash.
     display::test::DisplayManagerTestApi(shell->display_manager())
         .DisableChangeDisplayUponHostResize();
     DisplayConfigurationControllerTestApi(
         shell->display_configuration_controller())
         .DisableDisplayAnimator();
+  }
 
+  if (config_ == Config::CLASSIC) {
     // TODO: disabled for mash as AcceleratorControllerDelegateAura isn't
     // created in mash http://crbug.com/632111.
     test_screenshot_delegate_ = new TestScreenshotDelegate();
diff --git a/ash/wallpaper/wallpaper_controller.cc b/ash/wallpaper/wallpaper_controller.cc
index 2991f51..8ebe54a 100644
--- a/ash/wallpaper/wallpaper_controller.cc
+++ b/ash/wallpaper/wallpaper_controller.cc
@@ -416,14 +416,15 @@
 
 void WallpaperController::GetInternalDisplayCompositorLock() {
   if (display::Display::HasInternalDisplay()) {
-    compositor_lock_ =
-        Shell::Get()
-            ->window_tree_host_manager()
-            ->GetRootWindowForDisplayId(display::Display::InternalDisplayId())
-            ->layer()
-            ->GetCompositor()
-            ->GetCompositorLock(this, base::TimeDelta::FromMilliseconds(
-                                          kCompositorLockTimeoutMs));
+    aura::Window* root_window =
+        Shell::Get()->window_tree_host_manager()->GetRootWindowForDisplayId(
+            display::Display::InternalDisplayId());
+    if (root_window) {
+      compositor_lock_ =
+          root_window->layer()->GetCompositor()->GetCompositorLock(
+              this,
+              base::TimeDelta::FromMilliseconds(kCompositorLockTimeoutMs));
+    }
   }
 }
 
diff --git a/base/BUILD.gn b/base/BUILD.gn
index 1f9299c..9bdfd7c 100644
--- a/base/BUILD.gn
+++ b/base/BUILD.gn
@@ -2508,6 +2508,7 @@
       "android/java/src/org/chromium/base/ContentUriUtils.java",
       "android/java/src/org/chromium/base/ContextUtils.java",
       "android/java/src/org/chromium/base/CpuFeatures.java",
+      "android/java/src/org/chromium/base/DiscardableReferencePool.java",
       "android/java/src/org/chromium/base/EarlyTraceEvent.java",
       "android/java/src/org/chromium/base/EventLog.java",
       "android/java/src/org/chromium/base/FieldTrialList.java",
@@ -2666,6 +2667,7 @@
   junit_binary("base_junit_tests") {
     java_files = [
       "android/junit/src/org/chromium/base/BaseChromiumApplicationTest.java",
+      "android/junit/src/org/chromium/base/DiscardableReferencePoolTest.java",
       "android/junit/src/org/chromium/base/LogTest.java",
       "android/junit/src/org/chromium/base/NonThreadSafeTest.java",
       "android/junit/src/org/chromium/base/PromiseTest.java",
diff --git a/base/android/java/src/org/chromium/base/DiscardableReferencePool.java b/base/android/java/src/org/chromium/base/DiscardableReferencePool.java
new file mode 100644
index 0000000..566df70
--- /dev/null
+++ b/base/android/java/src/org/chromium/base/DiscardableReferencePool.java
@@ -0,0 +1,90 @@
+// 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.
+
+package org.chromium.base;
+
+import android.support.annotation.Nullable;
+
+import java.util.Collections;
+import java.util.Set;
+import java.util.WeakHashMap;
+
+/**
+ * A DiscardableReferencePool allows handing out typed references to objects ("payloads") that can
+ * be dropped in one batch ("drained"), e.g. under memory pressure. In contrast to {@link
+ * java.lang.ref.WeakReference}s, which drop their referents when they get garbage collected, a
+ * reference pool gives more precise control over when exactly it is drained.
+ *
+ * <p>Internally it uses a {@link WeakHashMap} with the reference itself as a key to allow the
+ * payloads to be garbage collected regularly when the last reference goes away before the pool is
+ * drained.
+ *
+ * <p>This class and its references are not thread-safe and should not be used simultaneously by
+ * multiple threads.
+ */
+public class DiscardableReferencePool {
+    /**
+     * The underlying data storage. The wildcard type parameter allows using a single pool for
+     * references of any type.
+     */
+    private final Set<DiscardableReference<?>> mPool;
+
+    public DiscardableReferencePool() {
+        WeakHashMap<DiscardableReference<?>, Boolean> map = new WeakHashMap<>();
+        mPool = Collections.newSetFromMap(map);
+    }
+
+    /**
+     * A reference to an object in the pool. Will be nulled out when the pool is drained.
+     * @param <T> The type of the object.
+     */
+    public static class DiscardableReference<T> {
+        @Nullable
+        private T mPayload;
+
+        private DiscardableReference(T payload) {
+            assert payload != null;
+            mPayload = payload;
+        }
+
+        /**
+         * @return The referent, or null if the pool has been drained.
+         */
+        @Nullable
+        public T get() {
+            return mPayload;
+        }
+
+        /**
+         * Clear the referent.
+         */
+        private void discard() {
+            assert mPayload != null;
+            mPayload = null;
+        }
+    }
+
+    /**
+     * @param <T> The type of the object.
+     * @param payload The payload to add to the pool.
+     * @return A new reference to the {@code payload}.
+     */
+    public <T> DiscardableReference<T> put(T payload) {
+        assert payload != null;
+        DiscardableReference<T> reference = new DiscardableReference<>(payload);
+        mPool.add(reference);
+        return reference;
+    }
+
+    /**
+     * Drains the pool, removing all references to objects in the pool and therefore allowing them
+     * to be garbage collected.
+     */
+    public void drain() {
+        for (DiscardableReference<?> ref : mPool) {
+            ref.discard();
+        }
+        mPool.clear();
+    }
+}
diff --git a/base/android/junit/src/org/chromium/base/DiscardableReferencePoolTest.java b/base/android/junit/src/org/chromium/base/DiscardableReferencePoolTest.java
new file mode 100644
index 0000000..48a23b5
--- /dev/null
+++ b/base/android/junit/src/org/chromium/base/DiscardableReferencePoolTest.java
@@ -0,0 +1,78 @@
+// 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.
+
+package org.chromium.base;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.annotation.Config;
+
+import org.chromium.base.DiscardableReferencePool.DiscardableReference;
+import org.chromium.testing.local.LocalRobolectricTestRunner;
+
+import java.lang.ref.WeakReference;
+
+/**
+ * Tests for {@link DiscardableReferencePool}.
+ */
+@RunWith(LocalRobolectricTestRunner.class)
+@Config(manifest = Config.NONE)
+public class DiscardableReferencePoolTest {
+    /**
+     * Tests that draining the pool clears references and allows objects to be garbage collected.
+     */
+    @Test
+    public void testDrain() {
+        DiscardableReferencePool pool = new DiscardableReferencePool();
+
+        Object object = new Object();
+        WeakReference<Object> weakReference = new WeakReference<>(object);
+
+        DiscardableReference<Object> discardableReference = pool.put(object);
+        Assert.assertEquals(object, discardableReference.get());
+
+        // Drop reference to the object itself, to allow it to be garbage-collected.
+        object = null;
+
+        pool.drain();
+
+        // The discardable reference should be null now.
+        Assert.assertNull(discardableReference.get());
+
+        // The object is not (strongly) reachable anymore, so the weak reference may or may not be
+        // null (it could be if a GC has happened since the pool was drained).
+        // After an explicit GC call it definitely should be null.
+        Runtime.getRuntime().gc();
+
+        Assert.assertNull(weakReference.get());
+    }
+
+    /**
+     * Tests that dropping the (last) discardable reference to an object allows it to be regularly
+     * garbage collected.
+     */
+    @Test
+    public void testReferenceGCd() {
+        DiscardableReferencePool pool = new DiscardableReferencePool();
+
+        Object object = new Object();
+        WeakReference<Object> weakReference = new WeakReference<>(object);
+
+        DiscardableReference<Object> discardableReference = pool.put(object);
+        Assert.assertEquals(object, discardableReference.get());
+
+        // Drop reference to the object itself and to the discardable reference, allowing the object
+        // to be garbage-collected.
+        object = null;
+        discardableReference = null;
+
+        // The object is not (strongly) reachable anymore, so the weak reference may or may not be
+        // null (it could be if a GC has happened since the pool was drained).
+        // After an explicit GC call it definitely should be null.
+        Runtime.getRuntime().gc();
+
+        Assert.assertNull(weakReference.get());
+    }
+}
diff --git a/base/i18n/icu_util_nacl_win64.cc b/base/i18n/icu_util_nacl_win64.cc
deleted file mode 100644
index 9ba8640..0000000
--- a/base/i18n/icu_util_nacl_win64.cc
+++ /dev/null
@@ -1,15 +0,0 @@
-// Copyright (c) 2009 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "base/i18n/icu_util.h"
-
-namespace base {
-namespace i18n {
-
-BASE_I18N_EXPORT bool InitializeICU() {
-  return true;
-}
-
-}  // namespace i18n
-}  // namespace base
diff --git a/build/android/pylib/local/device/local_device_environment.py b/build/android/pylib/local/device/local_device_environment.py
index 86ffc5f..d5536c7 100644
--- a/build/android/pylib/local/device/local_device_environment.py
+++ b/build/android/pylib/local/device/local_device_environment.py
@@ -94,7 +94,9 @@
     self._skip_clear_data = args.skip_clear_data
     self._target_devices_file = args.target_devices_file
     self._tool_name = args.tool
-    self._trace_output = args.trace_output
+    self._trace_output = None
+    if hasattr(args, 'trace_output'):
+      self._trace_output = args.trace_output
 
     devil_chromium.Initialize(
         output_directory=constants.GetOutDirectory(),
diff --git a/cc/layers/layer.cc b/cc/layers/layer.cc
index 6845f0e..a235729 100644
--- a/cc/layers/layer.cc
+++ b/cc/layers/layer.cc
@@ -699,11 +699,6 @@
   return GetMutatorHost()->ScrollOffsetAnimationWasInterrupted(element_id());
 }
 
-bool Layer::HasOnlyTranslationTransforms() const {
-  return GetMutatorHost()->HasOnlyTranslationTransforms(
-      element_id(), GetElementTypeForAnimation());
-}
-
 void Layer::SetScrollParent(Layer* parent) {
   DCHECK(IsPropertyChangeAllowed());
   if (inputs_.scroll_parent == parent)
diff --git a/cc/layers/layer.h b/cc/layers/layer.h
index 5812717..5d0c6d08 100644
--- a/cc/layers/layer.h
+++ b/cc/layers/layer.h
@@ -475,7 +475,6 @@
   bool FilterIsAnimating() const;
   bool TransformIsAnimating() const;
   bool ScrollOffsetAnimationWasInterrupted() const;
-  bool HasOnlyTranslationTransforms() const;
 
   void AddScrollChild(Layer* child);
   void RemoveScrollChild(Layer* child);
diff --git a/cc/layers/layer_impl.cc b/cc/layers/layer_impl.cc
index 3ee0f7534..5d2ed7e 100644
--- a/cc/layers/layer_impl.cc
+++ b/cc/layers/layer_impl.cc
@@ -484,7 +484,9 @@
       bool has_potential_animation = HasPotentiallyRunningTransformAnimation();
       if (node->has_potential_animation != has_potential_animation) {
         node->has_potential_animation = has_potential_animation;
-        node->has_only_translation_animations = HasOnlyTranslationTransforms();
+        node->has_only_translation_animations =
+            GetMutatorHost()->HasOnlyTranslationTransforms(
+                element_id(), GetElementTypeForAnimation());
         GetTransformTree().set_needs_update(true);
         layer_tree_impl()->set_needs_update_draw_properties();
       }
@@ -680,11 +682,6 @@
       element_id(), GetElementTypeForAnimation());
 }
 
-bool LayerImpl::HasOnlyTranslationTransforms() const {
-  return GetMutatorHost()->HasOnlyTranslationTransforms(
-      element_id(), GetElementTypeForAnimation());
-}
-
 bool LayerImpl::HasAnyAnimationTargetingProperty(
     TargetProperty::Type property) const {
   return GetMutatorHost()->HasAnyAnimationTargetingProperty(element_id(),
diff --git a/cc/layers/layer_impl.h b/cc/layers/layer_impl.h
index 2ed76e65..75e96c91 100644
--- a/cc/layers/layer_impl.h
+++ b/cc/layers/layer_impl.h
@@ -480,8 +480,6 @@
   gfx::Rect GetScaledEnclosingRectInTargetSpace(float scale) const;
 
  private:
-  bool HasOnlyTranslationTransforms() const;
-
   // This includes all animations, even those that are finished but haven't yet
   // been deleted.
   bool HasAnyAnimationTargetingProperty(TargetProperty::Type property) const;
diff --git a/cc/paint/paint_canvas.h b/cc/paint/paint_canvas.h
index e1fa9d0..b6f4c58 100644
--- a/cc/paint/paint_canvas.h
+++ b/cc/paint/paint_canvas.h
@@ -166,6 +166,8 @@
   virtual void drawDisplayItemList(
       scoped_refptr<DisplayItemList> display_item_list) = 0;
 
+  // Unlike SkCanvas::drawPicture, this only plays back the PaintRecord and does
+  // not add an additional clip.  This is closer to SkPicture::playback.
   virtual void drawPicture(sk_sp<const PaintRecord> record) = 0;
 
   virtual bool isClipEmpty() const = 0;
@@ -181,14 +183,6 @@
                         const SkRect& rect,
                         sk_sp<SkData> data) = 0;
 
-  // TODO(enne): maybe this should live on PaintRecord, but that's not
-  // possible when PaintRecord is a typedef.
-  virtual void PlaybackPaintRecord(sk_sp<const PaintRecord> record) = 0;
-
- protected:
-  friend class PaintSurface;
-  friend class PaintRecorder;
-
  private:
   DISALLOW_COPY_AND_ASSIGN(PaintCanvas);
 };
@@ -222,11 +216,6 @@
   int save_count_ = 0;
 };
 
-// TODO(enne): Move all these functions into PaintCanvas.  These are only
-// separate now to make the transition to concrete types easier by keeping
-// the base PaintCanvas type equivalent to the SkCanvas interface and
-// all these helper functions potentially operating on both.
-
 // Following routines are used in print preview workflow to mark the
 // preview metafile.
 #if defined(OS_MACOSX)
diff --git a/cc/paint/paint_op_buffer.cc b/cc/paint/paint_op_buffer.cc
index eb80ff0..d75981cf 100644
--- a/cc/paint/paint_op_buffer.cc
+++ b/cc/paint/paint_op_buffer.cc
@@ -340,6 +340,7 @@
 void DrawRecordOp::Raster(const PaintOp* base_op,
                           SkCanvas* canvas,
                           const SkMatrix& original_ctm) {
+  // Don't use drawPicture here, as it adds an implicit clip.
   auto* op = static_cast<const DrawRecordOp*>(base_op);
   op->record->playback(canvas);
 }
diff --git a/cc/paint/record_paint_canvas.cc b/cc/paint/record_paint_canvas.cc
index 5e768a0..ebc960c2 100644
--- a/cc/paint/record_paint_canvas.cc
+++ b/cc/paint/record_paint_canvas.cc
@@ -343,10 +343,6 @@
   buffer_->push<AnnotateOp>(type, rect, data);
 }
 
-void RecordPaintCanvas::PlaybackPaintRecord(sk_sp<const PaintRecord> record) {
-  drawPicture(record);
-}
-
 const SkNoDrawCanvas* RecordPaintCanvas::GetCanvas() const {
   return const_cast<RecordPaintCanvas*>(this)->GetCanvas();
 }
diff --git a/cc/paint/record_paint_canvas.h b/cc/paint/record_paint_canvas.h
index 4677512..a99b597 100644
--- a/cc/paint/record_paint_canvas.h
+++ b/cc/paint/record_paint_canvas.h
@@ -124,8 +124,6 @@
                 const SkRect& rect,
                 sk_sp<SkData> data) override;
 
-  void PlaybackPaintRecord(sk_sp<const PaintRecord> record) override;
-
   // Don't shadow non-virtual helper functions.
   using PaintCanvas::clipRect;
   using PaintCanvas::clipRRect;
diff --git a/cc/paint/skia_paint_canvas.cc b/cc/paint/skia_paint_canvas.cc
index 47953bd..9bcf3095 100644
--- a/cc/paint/skia_paint_canvas.cc
+++ b/cc/paint/skia_paint_canvas.cc
@@ -253,10 +253,6 @@
   return canvas_->getTotalMatrix();
 }
 
-void SkiaPaintCanvas::PlaybackPaintRecord(sk_sp<const PaintRecord> record) {
-  record->playback(canvas_);
-}
-
 void SkiaPaintCanvas::Annotate(AnnotationType type,
                                const SkRect& rect,
                                sk_sp<SkData> data) {
diff --git a/cc/paint/skia_paint_canvas.h b/cc/paint/skia_paint_canvas.h
index 720104df..1fd313b53 100644
--- a/cc/paint/skia_paint_canvas.h
+++ b/cc/paint/skia_paint_canvas.h
@@ -129,8 +129,6 @@
                 const SkRect& rect,
                 sk_sp<SkData> data) override;
 
-  void PlaybackPaintRecord(sk_sp<const PaintRecord> record) override;
-
   // Don't shadow non-virtual helper functions.
   using PaintCanvas::clipRect;
   using PaintCanvas::clipRRect;
diff --git a/cc/trees/layer_tree_host.cc b/cc/trees/layer_tree_host.cc
index 2b51bb3..7402ea2 100644
--- a/cc/trees/layer_tree_host.cc
+++ b/cc/trees/layer_tree_host.cc
@@ -1263,6 +1263,13 @@
 void LayerTreeHost::SetElementFilterMutated(ElementId element_id,
                                             ElementListType list_type,
                                             const FilterOperations& filters) {
+  if (settings_.use_layer_lists) {
+    // In SPv2 we always have property trees and can set the filter
+    // directly on the effect node.
+    property_trees_.effect_tree.OnFilterAnimated(element_id, filters);
+    return;
+  }
+
   Layer* layer = LayerByElementId(element_id);
   DCHECK(layer);
   layer->OnFilterAnimated(filters);
diff --git a/cc/trees/layer_tree_host_unittest.cc b/cc/trees/layer_tree_host_unittest.cc
index 46f45d5..a08d658 100644
--- a/cc/trees/layer_tree_host_unittest.cc
+++ b/cc/trees/layer_tree_host_unittest.cc
@@ -1180,6 +1180,95 @@
 
 SINGLE_THREAD_TEST_F(LayerTreeHostTestPropertyTreesChangedSync);
 
+class LayerTreeHostTestAnimationFilterMutatedNotUsingLayerLists
+    : public LayerTreeHostTest {
+ public:
+  void InitializeSettings(LayerTreeSettings* settings) override {
+    settings->use_layer_lists = false;
+  }
+
+ protected:
+  void SetupTree() override {
+    root_ = Layer::Create();
+    layer_tree_host()->SetRootLayer(root_);
+    LayerTreeHostTest::SetupTree();
+  }
+
+  void BeginTest() override {
+    FilterOperations filters;
+    EXPECT_EQ(FilterOperations(), root_->filters());
+    filters.Append(FilterOperation::CreateOpacityFilter(0.5f));
+    layer_tree_host()->SetElementFilterMutated(
+        root_->element_id(), ElementListType::ACTIVE, filters);
+    // When not using layer lists, filters are just stored directly on the
+    // layer.
+    EXPECT_EQ(filters, root_->filters());
+    EndTest();
+  }
+
+  void AfterTest() override {}
+
+ private:
+  scoped_refptr<Layer> root_;
+};
+
+SINGLE_THREAD_TEST_F(LayerTreeHostTestAnimationFilterMutatedNotUsingLayerLists);
+
+class LayerTreeHostTestAnimationFilterMutatedUsingLayerLists
+    : public LayerTreeHostTest {
+ public:
+  void InitializeSettings(LayerTreeSettings* settings) override {
+    settings->use_layer_lists = true;
+  }
+
+ protected:
+  void SetupTree() override {
+    root_ = Layer::Create();
+    layer_tree_host()->SetRootLayer(root_);
+    LayerTreeHostTest::SetupTree();
+  }
+
+  void BeginTest() override {
+    // Insert a dummy effect node to observe its mutation. This would
+    // normally have been created by PaintArtifactCompositor.
+    int effect_node_id =
+        layer_tree_host()->property_trees()->effect_tree.Insert(
+            EffectNode(), EffectTree::kInvalidNodeId);
+    layer_tree_host()
+        ->property_trees()
+        ->element_id_to_effect_node_index[root_->element_id()] = effect_node_id;
+
+    EXPECT_EQ(FilterOperations(), root_->filters());
+    EXPECT_EQ(FilterOperations(),
+              layer_tree_host()
+                  ->property_trees()
+                  ->effect_tree.FindNodeFromElementId(root_->element_id())
+                  ->filters);
+
+    FilterOperations filters;
+    filters.Append(FilterOperation::CreateOpacityFilter(0.5f));
+    layer_tree_host()->SetElementFilterMutated(
+        root_->element_id(), ElementListType::ACTIVE, filters);
+
+    // When using layer lists, we don't have to store the filters on the layer.
+    EXPECT_EQ(FilterOperations(), root_->filters());
+    // The filter should have been set directly on the effect node instead.
+    EXPECT_EQ(filters,
+              layer_tree_host()
+                  ->property_trees()
+                  ->effect_tree.FindNodeFromElementId(root_->element_id())
+                  ->filters);
+    EndTest();
+  }
+
+  void AfterTest() override {}
+
+ private:
+  scoped_refptr<Layer> root_;
+};
+
+SINGLE_THREAD_TEST_F(LayerTreeHostTestAnimationFilterMutatedUsingLayerLists);
+
 class LayerTreeHostTestEffectTreeSync : public LayerTreeHostTest {
  protected:
   void SetupTree() override {
@@ -1377,7 +1466,7 @@
 
     root_->SetBounds(gfx::Size(50, 50));
 
-    // Make sure child is registerd for animation.
+    // Make sure child is registered for animation.
     child_->SetElementId(ElementId(2));
 
     // Make sure child and grand_child have transform nodes.
diff --git a/chrome/VERSION b/chrome/VERSION
index a25da3cf..4b0ed428 100644
--- a/chrome/VERSION
+++ b/chrome/VERSION
@@ -1,4 +1,4 @@
 MAJOR=60
 MINOR=0
-BUILD=3097
+BUILD=3098
 PATCH=0
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeActivity.java
index 27c46ed6..c72cece 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeActivity.java
@@ -46,6 +46,7 @@
 import org.chromium.base.Callback;
 import org.chromium.base.CommandLine;
 import org.chromium.base.ContextUtils;
+import org.chromium.base.DiscardableReferencePool;
 import org.chromium.base.SysUtils;
 import org.chromium.base.TraceEvent;
 import org.chromium.base.VisibleForTesting;
@@ -272,6 +273,8 @@
     private int mScreenWidthDp;
     private Runnable mRecordMultiWindowModeScreenWidthRunnable;
 
+    private final DiscardableReferencePool mReferencePool = new DiscardableReferencePool();
+
     private AssistStatusHandler mAssistStatusHandler;
 
     // A set of views obscuring all tabs. When this set is nonempty,
@@ -1778,6 +1781,16 @@
         super.onBackPressed();
     }
 
+    @Override
+    public void onTrimMemory(int level) {
+        super.onTrimMemory(level);
+        // The conditions are expressed using ranges to capture intermediate levels possibly added
+        // to the API in the future.
+        if ((level >= TRIM_MEMORY_RUNNING_LOW && level < TRIM_MEMORY_UI_HIDDEN)
+                || level >= TRIM_MEMORY_MODERATE) {
+            mReferencePool.drain();
+        }
+    }
 
     private ContentViewCore getContentViewCore() {
         Tab tab = getActivityTab();
@@ -2203,4 +2216,11 @@
     public boolean supportsFullscreenActivity() {
         return false;
     }
+
+    /**
+     * @return the reference pool for this activity.
+     */
+    public DiscardableReferencePool getReferencePool() {
+        return mReferencePool;
+    }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/IntentHandler.java b/chrome/android/java/src/org/chromium/chrome/browser/IntentHandler.java
index db629e0..e0d73c9 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/IntentHandler.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/IntentHandler.java
@@ -589,14 +589,14 @@
      */
     public static void addTrustedIntentExtras(Intent intent) {
         if (ExternalNavigationDelegateImpl.willChromeHandleIntent(intent, true)) {
-            // The PendingIntent functions as an authentication token --- it could only have come
-            // from us. Stash it in the real Intent as an extra. shouldIgnoreIntent will retrieve it
-            // and check it with isIntentChromeInternal.
-            intent.putExtra(TRUSTED_APPLICATION_CODE_EXTRA, getAuthenticationToken());
             // It is crucial that we never leak the authentication token to other packages, because
             // then the other package could be used to impersonate us/do things as us. Therefore,
             // scope the real Intent to our package.
             intent.setPackage(ContextUtils.getApplicationContext().getPackageName());
+            // The PendingIntent functions as an authentication token --- it could only have come
+            // from us. Stash it in the real Intent as an extra. shouldIgnoreIntent will retrieve it
+            // and check it with isIntentChromeInternal.
+            intent.putExtra(TRUSTED_APPLICATION_CODE_EXTRA, getAuthenticationToken());
         }
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadManagerService.java b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadManagerService.java
index 541036dd..5c02497 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadManagerService.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadManagerService.java
@@ -1159,14 +1159,18 @@
 
             @Override
             protected void onPostExecute(Intent intent) {
-                if (intent == null || !ExternalNavigationDelegateImpl.resolveIntent(intent, true)
-                        || !DownloadUtils.fireOpenIntentForDownload(context, intent)
-                        || !hasDownloadManagerService()) {
+                boolean didLaunchIntent = intent != null
+                        && ExternalNavigationDelegateImpl.resolveIntent(intent, true)
+                        && DownloadUtils.fireOpenIntentForDownload(context, intent);
+
+                if (!didLaunchIntent) {
                     openDownloadsPage(context);
-                } else {
-                    DownloadManagerService service =
-                            DownloadManagerService.getDownloadManagerService();
-                    service.updateLastAccessTime(downloadGuid, isOffTheRecord);
+                    return;
+                }
+
+                if (didLaunchIntent && hasDownloadManagerService()) {
+                    DownloadManagerService.getDownloadManagerService().updateLastAccessTime(
+                            downloadGuid, isOffTheRecord);
                 }
             }
         }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadUtils.java b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadUtils.java
index fa24c4ff..950154b 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadUtils.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadUtils.java
@@ -27,6 +27,7 @@
 import org.chromium.base.FileUtils;
 import org.chromium.base.Log;
 import org.chromium.base.VisibleForTesting;
+import org.chromium.base.library_loader.LibraryProcessType;
 import org.chromium.base.metrics.RecordHistogram;
 import org.chromium.base.metrics.RecordUserAction;
 import org.chromium.chrome.R;
@@ -54,6 +55,7 @@
 import org.chromium.components.feature_engagement_tracker.FeatureEngagementTracker;
 import org.chromium.components.offline_items_collection.OfflineItem.Progress;
 import org.chromium.components.offline_items_collection.OfflineItemProgressUnit;
+import org.chromium.content.browser.BrowserStartupController;
 import org.chromium.content_public.browser.DownloadState;
 import org.chromium.content_public.browser.LoadUrlParams;
 import org.chromium.ui.base.DeviceFormFactor;
@@ -170,10 +172,13 @@
             }
         }
 
-        Profile profile = (tab == null ? Profile.getLastUsedProfile() : tab.getProfile());
-        FeatureEngagementTracker tracker =
-                FeatureEngagementTrackerFactory.getFeatureEngagementTrackerForProfile(profile);
-        tracker.notifyEvent(EventConstants.DOWNLOAD_HOME_OPENED);
+        if (BrowserStartupController.get(LibraryProcessType.PROCESS_BROWSER)
+                        .isStartupSuccessfullyCompleted()) {
+            Profile profile = (tab == null ? Profile.getLastUsedProfile() : tab.getProfile());
+            FeatureEngagementTracker tracker =
+                    FeatureEngagementTrackerFactory.getFeatureEngagementTrackerForProfile(profile);
+            tracker.notifyEvent(EventConstants.DOWNLOAD_HOME_OPENED);
+        }
 
         return true;
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/infobar/TranslateCompactInfoBar.java b/chrome/android/java/src/org/chromium/chrome/browser/infobar/TranslateCompactInfoBar.java
index fbadb25..0389b7f 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/infobar/TranslateCompactInfoBar.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/infobar/TranslateCompactInfoBar.java
@@ -40,8 +40,8 @@
     // showing language menu after dismissing overflow menu.
     private TranslateMenuHelper mOverflowMenuHelper;
     private TranslateMenuHelper mLanguageMenuHelper;
-
     private TintedImageButton mMenuButton;
+    private boolean mUserInteracted;
 
     /** The controller for translate UI snackbars. */
     class TranslateSnackbarController implements SnackbarController {
@@ -98,6 +98,7 @@
         if (mInitialStep == TRANSLATING_INFOBAR) {
             mTabLayout.getTabAt(TARGET_TAB_INDEX).select();
             mTabLayout.showProgressBarOnTab(TARGET_TAB_INDEX);
+            mUserInteracted = true;
         }
 
         mTabLayout.addOnTabSelectedListener(this);
@@ -134,11 +135,12 @@
         }
     }
 
-    private void startTranslating(int tabPostion) {
-        if (TARGET_TAB_INDEX == tabPostion) {
+    private void startTranslating(int tabPosition) {
+        if (TARGET_TAB_INDEX == tabPosition) {
             // Already on the target tab.
             mTabLayout.showProgressBarOnTab(TARGET_TAB_INDEX);
             onButtonClicked(ActionType.TRANSLATE);
+            mUserInteracted = true;
         } else {
             mTabLayout.getTabAt(TARGET_TAB_INDEX).select();
         }
@@ -165,6 +167,13 @@
         mNativeTranslateInfoBarPtr = nativePtr;
     }
 
+    @CalledByNative
+    private void setAutoAlwaysTranslate() {
+        createAndShowSnackbar(getContext().getString(R.string.translate_snackbar_always_translate,
+                                      mOptions.sourceLanguageName(), mOptions.targetLanguageName()),
+                Snackbar.UMA_TRANSLATE_ALWAYS, TranslateMenu.ID_OVERFLOW_ALWAYS_TRANSLATE);
+    }
+
     @Override
     protected void onNativeDestroyed() {
         mNativeTranslateInfoBarPtr = 0;
@@ -172,6 +181,14 @@
     }
 
     @Override
+    public void onCloseButtonClicked() {
+        if (!mUserInteracted) {
+            onButtonClicked(ActionType.CANCEL);
+        }
+        super.onCloseButtonClicked();
+    }
+
+    @Override
     public void onTabSelected(TabLayout.Tab tab) {
         switch (tab.getPosition()) {
             case SOURCE_TAB_INDEX:
@@ -193,6 +210,7 @@
 
     @Override
     public void onOverflowMenuItemClicked(int itemId) {
+        mUserInteracted = true;
         switch (itemId) {
             case TranslateMenu.ID_OVERFLOW_MORE_LANGUAGE:
                 initMenuHelper(TranslateMenu.MENU_TARGET_LANGUAGE);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPage.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPage.java
index 36d91077..d4b177f 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPage.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPage.java
@@ -18,6 +18,7 @@
 
 import org.chromium.base.ApiCompatibilityUtils;
 import org.chromium.base.CommandLine;
+import org.chromium.base.DiscardableReferencePool;
 import org.chromium.base.Log;
 import org.chromium.base.TraceEvent;
 import org.chromium.base.VisibleForTesting;
@@ -178,8 +179,9 @@
         public NewTabPageManagerImpl(SuggestionsSource suggestionsSource,
                 SuggestionsEventReporter eventReporter,
                 SuggestionsNavigationDelegate navigationDelegate, Profile profile,
-                NativePageHost nativePageHost) {
-            super(suggestionsSource, eventReporter, navigationDelegate, profile, nativePageHost);
+                NativePageHost nativePageHost, DiscardableReferencePool referencePool) {
+            super(suggestionsSource, eventReporter, navigationDelegate, profile, nativePageHost,
+                    referencePool);
         }
 
         @Override
@@ -322,8 +324,8 @@
         SuggestionsNavigationDelegateImpl navigationDelegate =
                 new SuggestionsNavigationDelegateImpl(
                         activity, profile, nativePageHost, tabModelSelector);
-        mNewTabPageManager = new NewTabPageManagerImpl(
-                mSnippetsBridge, eventReporter, navigationDelegate, profile, nativePageHost);
+        mNewTabPageManager = new NewTabPageManagerImpl(mSnippetsBridge, eventReporter,
+                navigationDelegate, profile, nativePageHost, activity.getReferencePool());
         mTileGroupDelegate = new NewTabPageTileGroupDelegate(
                 activity, profile, tabModelSelector, navigationDelegate);
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SnippetArticle.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SnippetArticle.java
index 8f406b7..fa1d6d1 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SnippetArticle.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SnippetArticle.java
@@ -6,6 +6,7 @@
 import android.graphics.Bitmap;
 import android.support.annotation.Nullable;
 
+import org.chromium.base.DiscardableReferencePool.DiscardableReference;
 import org.chromium.chrome.browser.suggestions.OfflinableSuggestion;
 
 import java.io.File;
@@ -51,7 +52,7 @@
     private int mGlobalRank = -1;
 
     /** Bitmap of the thumbnail, fetched lazily, when the RecyclerView wants to show the snippet. */
-    private Bitmap mThumbnailBitmap;
+    private DiscardableReference<Bitmap> mThumbnailBitmap;
 
     /** Stores whether impression of this article has been tracked already. */
     private boolean mImpressionTracked;
@@ -108,11 +109,11 @@
      * initially unset.
      */
     public Bitmap getThumbnailBitmap() {
-        return mThumbnailBitmap;
+        return mThumbnailBitmap == null ? null : mThumbnailBitmap.get();
     }
 
     /** Sets the thumbnail bitmap for this article. */
-    public void setThumbnailBitmap(Bitmap bitmap) {
+    public void setThumbnailBitmap(DiscardableReference<Bitmap> bitmap) {
         mThumbnailBitmap = bitmap;
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SnippetArticleViewHolder.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SnippetArticleViewHolder.java
index 2035b23..aa9e5dd 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SnippetArticleViewHolder.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SnippetArticleViewHolder.java
@@ -357,7 +357,7 @@
             mArticle.setThumbnailBitmap(null);
             Bitmap thumbnail = mThumbnailProvider.getThumbnail(mImageCallback);
             if (thumbnail == null || thumbnail.isRecycled()) return;
-            mArticle.setThumbnailBitmap(thumbnail);
+            mArticle.setThumbnailBitmap(mUiDelegate.getReferencePool().put(thumbnail));
             setThumbnailFromBitmap(thumbnail);
 
             return;
@@ -372,8 +372,9 @@
 
         // mThumbnailView's visibility is modified in updateLayout().
         if (mThumbnailView.getVisibility() != View.VISIBLE) return;
-        if (mArticle.getThumbnailBitmap() != null && !mArticle.getThumbnailBitmap().isRecycled()) {
-            setThumbnailFromBitmap(mArticle.getThumbnailBitmap());
+        Bitmap thumbnail = mArticle.getThumbnailBitmap();
+        if (thumbnail != null && !thumbnail.isRecycled()) {
+            setThumbnailFromBitmap(thumbnail);
             return;
         }
 
@@ -419,7 +420,7 @@
                 thumbnail, targetSize, targetSize, ThumbnailUtils.OPTIONS_RECYCLE_INPUT);
 
         // Store the bitmap to skip the download task next time we display this snippet.
-        snippet.setThumbnailBitmap(scaledThumbnail);
+        snippet.setThumbnailBitmap(mUiDelegate.getReferencePool().put(scaledThumbnail));
 
         // Cross-fade between the placeholder and the thumbnail. We cross-fade because the incoming
         // image may have transparency and we don't want the previous image showing up behind.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/AccessibilityPreferences.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/AccessibilityPreferences.java
index e75c41d..fea1c97 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/AccessibilityPreferences.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/AccessibilityPreferences.java
@@ -8,6 +8,7 @@
 import android.preference.Preference;
 import android.preference.Preference.OnPreferenceChangeListener;
 import android.preference.PreferenceFragment;
+import android.widget.ListView;
 
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.accessibility.FontSizePrefs;
@@ -61,6 +62,13 @@
     }
 
     @Override
+    public void onActivityCreated(Bundle savedInstanceState) {
+        super.onActivityCreated(savedInstanceState);
+
+        ((ListView) getView().findViewById(android.R.id.list)).setItemsCanFocus(true);
+    }
+
+    @Override
     public void onStart() {
         super.onStart();
         updateValues();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/privacy/ClearBrowsingDataPreferences.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/privacy/ClearBrowsingDataPreferences.java
index 5e7efcef..1741ee2 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/privacy/ClearBrowsingDataPreferences.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/privacy/ClearBrowsingDataPreferences.java
@@ -624,8 +624,11 @@
         // Now that the dialog's view has been created, update the button state.
         updateButtonState();
 
-        // Remove the dividers between checkboxes.
-        ((ListView) getView().findViewById(android.R.id.list)).setDivider(null);
+        // Remove the dividers between checkboxes, and make sure the individual widgets can be
+        // focused.
+        ListView view = (ListView) getView().findViewById(android.R.id.list);
+        view.setDivider(null);
+        view.setItemsCanFocus(true);
     }
 
     @Override
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsBottomSheetContent.java b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsBottomSheetContent.java
index 6c10e4a5..74203ea 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsBottomSheetContent.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsBottomSheetContent.java
@@ -12,6 +12,7 @@
 import android.view.View;
 
 import org.chromium.base.ApiCompatibilityUtils;
+import org.chromium.base.DiscardableReferencePool;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.ChromeActivity;
 import org.chromium.chrome.browser.NativePageHost;
@@ -56,7 +57,8 @@
                 new SuggestionsNavigationDelegateImpl(activity, profile, sheet, tabModelSelector);
         mTileGroupDelegate = new TileGroupDelegateImpl(
                 activity, profile, tabModelSelector, navigationDelegate, snackbarManager);
-        mSuggestionsUiDelegate = createSuggestionsDelegate(profile, navigationDelegate, sheet);
+        mSuggestionsUiDelegate = createSuggestionsDelegate(
+                profile, navigationDelegate, sheet, activity.getReferencePool());
 
         mView = LayoutInflater.from(activity).inflate(
                 R.layout.suggestions_bottom_sheet_content, null);
@@ -179,7 +181,8 @@
     }
 
     private static SuggestionsUiDelegateImpl createSuggestionsDelegate(Profile profile,
-            SuggestionsNavigationDelegate navigationDelegate, NativePageHost host) {
+            SuggestionsNavigationDelegate navigationDelegate, NativePageHost host,
+            DiscardableReferencePool referencePool) {
         SnippetsBridge snippetsBridge = null;
         SuggestionsSource suggestionsSource;
         SuggestionsEventReporter eventReporter;
@@ -198,7 +201,7 @@
         }
 
         SuggestionsUiDelegateImpl delegate = new SuggestionsUiDelegateImpl(
-                suggestionsSource, eventReporter, navigationDelegate, profile, host);
+                suggestionsSource, eventReporter, navigationDelegate, profile, host, referencePool);
         if (snippetsBridge != null) delegate.addDestructionObserver(snippetsBridge);
 
         return delegate;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsUiDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsUiDelegate.java
index b0579b6e..fce6d50 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsUiDelegate.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsUiDelegate.java
@@ -4,6 +4,7 @@
 
 package org.chromium.chrome.browser.suggestions;
 
+import org.chromium.base.DiscardableReferencePool;
 import org.chromium.chrome.browser.favicon.FaviconHelper.FaviconImageCallback;
 import org.chromium.chrome.browser.favicon.FaviconHelper.IconAvailabilityCallback;
 import org.chromium.chrome.browser.favicon.LargeIconBridge.LargeIconCallback;
@@ -29,6 +30,12 @@
     /** Convenience method to access the {@link SuggestionsNavigationDelegate}. */
     SuggestionsNavigationDelegate getNavigationDelegate();
 
+    /**
+     * @return The reference pool to use for large objects that should be dropped under
+     * memory pressure.
+     */
+    DiscardableReferencePool getReferencePool();
+
     // Favicons
 
     /**
@@ -65,6 +72,6 @@
      */
     void addDestructionObserver(DestructionObserver destructionObserver);
 
-    /** @return whether the suggestions UI is currently visible. */
+    /** @return Whether the suggestions UI is currently visible. */
     boolean isVisible();
 }
\ No newline at end of file
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsUiDelegateImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsUiDelegateImpl.java
index 37706e6c..ab376ce 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsUiDelegateImpl.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsUiDelegateImpl.java
@@ -6,6 +6,7 @@
 
 import android.support.annotation.Nullable;
 
+import org.chromium.base.DiscardableReferencePool;
 import org.chromium.chrome.browser.NativePageHost;
 import org.chromium.chrome.browser.favicon.FaviconHelper;
 import org.chromium.chrome.browser.favicon.FaviconHelper.FaviconImageCallback;
@@ -32,6 +33,8 @@
 
     private final NativePageHost mHost;
 
+    private final DiscardableReferencePool mReferencePool;
+
     private FaviconHelper mFaviconHelper;
     private LargeIconBridge mLargeIconBridge;
 
@@ -39,8 +42,8 @@
 
     public SuggestionsUiDelegateImpl(SuggestionsSource suggestionsSource,
             SuggestionsEventReporter eventReporter,
-            SuggestionsNavigationDelegate navigationDelegate, Profile profile,
-            NativePageHost host) {
+            SuggestionsNavigationDelegate navigationDelegate, Profile profile, NativePageHost host,
+            DiscardableReferencePool referencePool) {
         mSuggestionsSource = suggestionsSource;
         mSuggestionsRanker = new SuggestionsRanker();
         mSuggestionsEventReporter = eventReporter;
@@ -48,6 +51,7 @@
 
         mProfile = profile;
         mHost = host;
+        mReferencePool = referencePool;
     }
 
     @Override
@@ -97,6 +101,11 @@
     }
 
     @Override
+    public DiscardableReferencePool getReferencePool() {
+        return mReferencePool;
+    }
+
+    @Override
     public void addDestructionObserver(DestructionObserver destructionObserver) {
         mDestructionObservers.add(destructionObserver);
     }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/snippets/ArticleSnippetsTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/snippets/ArticleSnippetsTest.java
index 8fd2267..cb7a4410 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/snippets/ArticleSnippetsTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/snippets/ArticleSnippetsTest.java
@@ -4,6 +4,7 @@
 
 package org.chromium.chrome.browser.ntp.snippets;
 
+import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
 import android.support.test.InstrumentationRegistry;
 import android.support.test.filters.MediumTest;
@@ -16,6 +17,7 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import org.chromium.base.DiscardableReferencePool;
 import org.chromium.base.ThreadUtils;
 import org.chromium.base.test.util.CommandLineFlags;
 import org.chromium.base.test.util.Feature;
@@ -146,9 +148,11 @@
                 1466614774, // Publish timestamp
                 10f, // Score
                 1466634774); // Fetch timestamp
-        shortSnippet.setThumbnailBitmap(
+
+        Bitmap thumbnail =
                 BitmapFactory.decodeResource(mActivityTestRule.getActivity().getResources(),
-                        R.drawable.signin_promo_illustration));
+                        R.drawable.signin_promo_illustration);
+        shortSnippet.setThumbnailBitmap(mUiDelegate.getReferencePool().put(thumbnail));
 
         SnippetArticle longSnippet = new SnippetArticle(fullCategory, "id2",
                 new String(new char[20]).replace("\0", "Snippet "),
@@ -206,6 +210,7 @@
         private SuggestionsEventReporter mSuggestionsEventReporter =
                 new DummySuggestionsEventReporter();
         private SuggestionsRanker mSuggestionsRanker = new SuggestionsRanker();
+        private final DiscardableReferencePool mReferencePool = new DiscardableReferencePool();
 
         @Override
         public void getLocalFaviconImageForURL(
@@ -246,6 +251,11 @@
         }
 
         @Override
+        public DiscardableReferencePool getReferencePool() {
+            return mReferencePool;
+        }
+
+        @Override
         public void addDestructionObserver(DestructionObserver destructionObserver) {}
 
         @Override
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index 3aab0f0..cdb9db1 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -45,6 +45,7 @@
       "netapi32.lib",
       "ndfapi.lib",  # Used by browser/net/net_error_diagnostics_dialog_win.h
       "pdh.lib",  # Used by browser/private_working_set_snapshot.h
+      "msi.lib",  # Used by browser/conflicts/msi_util_win.h
     ]
     ldflags = [
       "/DELAYLOAD:ndfapi.dll",
@@ -273,6 +274,8 @@
     "conflicts/module_info_win.h",
     "conflicts/module_inspector_win.cc",
     "conflicts/module_inspector_win.h",
+    "conflicts/msi_util_win.cc",
+    "conflicts/msi_util_win.h",
     "content_settings/chrome_content_settings_utils.cc",
     "content_settings/chrome_content_settings_utils.h",
     "content_settings/cookie_settings_factory.cc",
diff --git a/chrome/browser/conflicts/msi_util_win.cc b/chrome/browser/conflicts/msi_util_win.cc
new file mode 100644
index 0000000..4ecc997
--- /dev/null
+++ b/chrome/browser/conflicts/msi_util_win.cc
@@ -0,0 +1,156 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/conflicts/msi_util_win.h"
+
+#include <windows.h>
+
+#include <msi.h>
+#include <msiquery.h>
+
+#include <utility>
+
+#include "base/strings/string_util.h"
+#include "base/threading/thread_restrictions.h"
+
+namespace {
+
+// Most strings returned by the MSI API are smaller than this value, so only
+// 1 call to the API is needed in the common case.
+constexpr DWORD kBufferInitialSize = 256;
+
+// Retrieves the file path to the product's installer.
+bool GetMsiPath(const base::string16& product_guid, base::string16* result) {
+  DWORD buffer_size = kBufferInitialSize;
+  UINT ret =
+      ::MsiGetProductInfo(product_guid.c_str(), INSTALLPROPERTY_LOCALPACKAGE,
+                          base::WriteInto(result, buffer_size), &buffer_size);
+  if (ret == ERROR_MORE_DATA) {
+    // Must account for the null terminator.
+    buffer_size++;
+
+    ret =
+        ::MsiGetProductInfo(product_guid.c_str(), INSTALLPROPERTY_LOCALPACKAGE,
+                            base::WriteInto(result, buffer_size), &buffer_size);
+  }
+
+  if (ret == ERROR_SUCCESS) {
+    result->resize(buffer_size);
+    return true;
+  }
+  return false;
+}
+
+// Returns the string value at position |index| in the given |record_handle|.
+// Note that columns are 1-indexed.
+bool GetRecordString(MSIHANDLE record_handle,
+                     size_t index,
+                     base::string16* result) {
+  DWORD buffer_size = kBufferInitialSize;
+  UINT ret = ::MsiRecordGetString(
+      record_handle, index, base::WriteInto(result, buffer_size), &buffer_size);
+  if (ret == ERROR_MORE_DATA) {
+    // Must account for the null terminator.
+    buffer_size++;
+
+    ret = ::MsiRecordGetString(record_handle, index,
+                               base::WriteInto(result, buffer_size),
+                               &buffer_size);
+  }
+
+  if (ret == ERROR_SUCCESS) {
+    result->resize(buffer_size);
+    return true;
+  }
+  return false;
+}
+
+// Inspects the installer file and extracts the component guids. Each .msi file
+// is actually an SQL database.
+bool GetMsiComponentGuids(const base::string16& msi_database_path,
+                          std::vector<base::string16>* component_guids) {
+  PMSIHANDLE msi_database_handle;
+  if (::MsiOpenDatabase(msi_database_path.c_str(), MSIDBOPEN_READONLY,
+                        &msi_database_handle) != ERROR_SUCCESS) {
+    return false;
+  }
+
+  PMSIHANDLE components_view_handle;
+  if (::MsiDatabaseOpenView(msi_database_handle,
+                            L"SELECT ComponentId FROM Component",
+                            &components_view_handle) != ERROR_SUCCESS) {
+    return false;
+  }
+
+  if (::MsiViewExecute(components_view_handle, 0) != ERROR_SUCCESS)
+    return false;
+
+  PMSIHANDLE record_handle;
+  while (::MsiViewFetch(components_view_handle, &record_handle) ==
+         ERROR_SUCCESS) {
+    // The record only have the ComponentId column, and its index is 1.
+    base::string16 component_guid;
+    if (GetRecordString(record_handle, 1, &component_guid))
+      component_guids->push_back(std::move(component_guid));
+  }
+
+  return true;
+}
+
+// Retrieves the |path| to the given component.
+bool GetMsiComponentPath(const base::string16& product_guid,
+                         const base::string16& component_guid,
+                         base::string16* path) {
+  DWORD buffer_size = kBufferInitialSize;
+  INSTALLSTATE ret =
+      ::MsiGetComponentPath(product_guid.c_str(), component_guid.c_str(),
+                            base::WriteInto(path, buffer_size), &buffer_size);
+  if (ret == INSTALLSTATE_MOREDATA) {
+    // Must account for the null terminator.
+    buffer_size++;
+
+    ret =
+        ::MsiGetComponentPath(product_guid.c_str(), component_guid.c_str(),
+                              base::WriteInto(path, buffer_size), &buffer_size);
+  }
+
+  if (ret == INSTALLSTATE_LOCAL) {
+    path->resize(buffer_size);
+    return true;
+  }
+  return false;
+}
+
+}  // namespace
+
+// The most efficient way to get the list of components associated to an
+// installed product is to inspect the installer file. A copy of the installer
+// exists somewhere on the file system because Windows needs it to uninstall the
+// product.
+//
+// So this function retrieves the path to the installer, extracts the component
+// GUIDS from it, and uses those to find the path of each component.
+bool MsiUtil::GetMsiComponentPaths(
+    const base::string16& product_guid,
+    std::vector<base::string16>* component_paths) {
+  base::ThreadRestrictions::AssertIOAllowed();
+
+  base::string16 msi_path;
+  if (!GetMsiPath(product_guid, &msi_path))
+    return false;
+
+  std::vector<base::string16> component_guids;
+  if (!GetMsiComponentGuids(msi_path, &component_guids))
+    return false;
+
+  for (const auto& component_guid : component_guids) {
+    base::string16 component_path;
+    if (!GetMsiComponentPath(product_guid, component_guid, &component_path))
+      continue;
+
+    component_paths->push_back(std::move(component_path));
+  }
+
+  return true;
+}
diff --git a/chrome/browser/conflicts/msi_util_win.h b/chrome/browser/conflicts/msi_util_win.h
new file mode 100644
index 0000000..4045cd6
--- /dev/null
+++ b/chrome/browser/conflicts/msi_util_win.h
@@ -0,0 +1,26 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_CONFLICTS_MSI_UTIL_WIN_H_
+#define CHROME_BROWSER_CONFLICTS_MSI_UTIL_WIN_H_
+
+#include <vector>
+
+#include "base/callback.h"
+#include "base/strings/string16.h"
+
+class MsiUtil {
+ public:
+  // Using the Microsoft Installer API, retrieves the path of all the components
+  // for a given product. This function should be called on a thread that allows
+  // access to the file system. Returns false if any error occured, including if
+  // the |product_guid| passed is not a GUID.
+  //
+  // Note: Marked virtual to allow mocking.
+  virtual bool GetMsiComponentPaths(
+      const base::string16& product_guid,
+      std::vector<base::string16>* component_paths);
+};
+
+#endif  // CHROME_BROWSER_CONFLICTS_MSI_UTIL_WIN_H_
diff --git a/chrome/browser/password_manager/chrome_password_manager_client_unittest.cc b/chrome/browser/password_manager/chrome_password_manager_client_unittest.cc
index a1216c84..a6b5270 100644
--- a/chrome/browser/password_manager/chrome_password_manager_client_unittest.cc
+++ b/chrome/browser/password_manager/chrome_password_manager_client_unittest.cc
@@ -177,7 +177,7 @@
       const autofill::FormsPredictionsMap& predictions) override {}
 
   void FindFocusedPasswordForm(
-      const FindFocusedPasswordFormCallback& callback) override {}
+      FindFocusedPasswordFormCallback callback) override {}
 
   // Records whether SetLoggingState() gets called.
   bool called_set_logging_state_;
diff --git a/chrome/browser/permissions/grouped_permission_infobar_delegate_android.cc b/chrome/browser/permissions/grouped_permission_infobar_delegate_android.cc
index 31b01c9..aa098ea 100644
--- a/chrome/browser/permissions/grouped_permission_infobar_delegate_android.cc
+++ b/chrome/browser/permissions/grouped_permission_infobar_delegate_android.cc
@@ -31,7 +31,7 @@
 }
 
 size_t GroupedPermissionInfoBarDelegate::PermissionCount() const {
-  return permission_prompt_->permission_count();
+  return permission_prompt_->PermissionCount();
 }
 
 bool GroupedPermissionInfoBarDelegate::ShouldShowPersistenceToggle() const {
diff --git a/chrome/browser/permissions/permission_prompt_android.cc b/chrome/browser/permissions/permission_prompt_android.cc
index 98a1048..e042101 100644
--- a/chrome/browser/permissions/permission_prompt_android.cc
+++ b/chrome/browser/permissions/permission_prompt_android.cc
@@ -21,17 +21,14 @@
   delegate_ = delegate;
 }
 
-void PermissionPromptAndroid::Show(
-    const std::vector<PermissionRequest*>& requests,
-    const std::vector<bool>& values) {
+void PermissionPromptAndroid::Show() {
   InfoBarService* infobar_service =
       InfoBarService::FromWebContents(web_contents_);
   if (!infobar_service)
     return;
 
-  requests_ = requests;
-  GroupedPermissionInfoBarDelegate::Create(this, infobar_service,
-                                           requests[0]->GetOrigin());
+  GroupedPermissionInfoBarDelegate::Create(
+      this, infobar_service, delegate_->Requests()[0]->GetOrigin());
 }
 
 bool PermissionPromptAndroid::CanAcceptRequestUpdate() {
@@ -58,7 +55,6 @@
 }
 
 void PermissionPromptAndroid::Closing() {
-  requests_.clear();
   if (delegate_)
     delegate_->Closing();
 }
@@ -69,32 +65,37 @@
 }
 
 void PermissionPromptAndroid::Accept() {
-  requests_.clear();
   if (delegate_)
     delegate_->Accept();
 }
 
 void PermissionPromptAndroid::Deny() {
-  requests_.clear();
   if (delegate_)
     delegate_->Deny();
 }
 
+size_t PermissionPromptAndroid::PermissionCount() const {
+  return delegate_->Requests().size();
+}
+
 ContentSettingsType PermissionPromptAndroid::GetContentSettingType(
     size_t position) const {
-  DCHECK_LT(position, requests_.size());
-  return requests_[position]->GetContentSettingsType();
+  const std::vector<PermissionRequest*>& requests = delegate_->Requests();
+  DCHECK_LT(position, requests.size());
+  return requests[position]->GetContentSettingsType();
 }
 
 int PermissionPromptAndroid::GetIconIdForPermission(size_t position) const {
-  DCHECK_LT(position, requests_.size());
-  return requests_[position]->GetIconId();
+  const std::vector<PermissionRequest*>& requests = delegate_->Requests();
+  DCHECK_LT(position, requests.size());
+  return requests[position]->GetIconId();
 }
 
 base::string16 PermissionPromptAndroid::GetMessageTextFragment(
     size_t position) const {
-  DCHECK_LT(position, requests_.size());
-  return requests_[position]->GetMessageTextFragment();
+  const std::vector<PermissionRequest*>& requests = delegate_->Requests();
+  DCHECK_LT(position, requests.size());
+  return requests[position]->GetMessageTextFragment();
 }
 
 // static
diff --git a/chrome/browser/permissions/permission_prompt_android.h b/chrome/browser/permissions/permission_prompt_android.h
index 66e5317..ab47330e 100644
--- a/chrome/browser/permissions/permission_prompt_android.h
+++ b/chrome/browser/permissions/permission_prompt_android.h
@@ -11,8 +11,6 @@
 #include "chrome/browser/ui/permission_bubble/permission_prompt.h"
 #include "components/content_settings/core/common/content_settings_types.h"
 
-class PermissionRequest;
-
 namespace content {
 class WebContents;
 }
@@ -24,8 +22,7 @@
 
   // PermissionPrompt:
   void SetDelegate(Delegate* delegate) override;
-  void Show(const std::vector<PermissionRequest*>& requests,
-            const std::vector<bool>& accept_state) override;
+  void Show() override;
   bool CanAcceptRequestUpdate() override;
   bool HidesAutomatically() override;
   void Hide() override;
@@ -37,7 +34,7 @@
   void Accept();
   void Deny();
 
-  size_t permission_count() const { return requests_.size(); }
+  size_t PermissionCount() const;
   ContentSettingsType GetContentSettingType(size_t position) const;
   int GetIconIdForPermission(size_t position) const;
   base::string16 GetMessageTextFragment(size_t position) const;
@@ -49,8 +46,6 @@
   content::WebContents* web_contents_;
   // |delegate_| is the PermissionRequestManager, which owns this object.
   Delegate* delegate_;
-  // The current request being displayed (if any).
-  std::vector<PermissionRequest*> requests_;
 
   DISALLOW_COPY_AND_ASSIGN(PermissionPromptAndroid);
 };
diff --git a/chrome/browser/permissions/permission_request_manager.cc b/chrome/browser/permissions/permission_request_manager.cc
index ad680b8..51fe1ba 100644
--- a/chrome/browser/permissions/permission_request_manager.cc
+++ b/chrome/browser/permissions/permission_request_manager.cc
@@ -313,6 +313,14 @@
   // returning from this function is the only safe thing to do.
 }
 
+const std::vector<PermissionRequest*>& PermissionRequestManager::Requests() {
+  return requests_;
+}
+
+const std::vector<bool>& PermissionRequestManager::AcceptStates() {
+  return accept_states_;
+}
+
 void PermissionRequestManager::ToggleAccept(int request_index, bool new_value) {
   DCHECK(request_index < static_cast<int>(accept_states_.size()));
   accept_states_[request_index] = new_value;
@@ -400,7 +408,7 @@
   DCHECK(!requests_.empty());
   DCHECK(main_frame_has_fully_loaded_);
 
-  view_->Show(requests_, accept_states_);
+  view_->Show();
   PermissionUmaUtil::PermissionPromptShown(requests_);
   NotifyBubbleAdded();
 
diff --git a/chrome/browser/permissions/permission_request_manager.h b/chrome/browser/permissions/permission_request_manager.h
index af2d8642..ffc4af1 100644
--- a/chrome/browser/permissions/permission_request_manager.h
+++ b/chrome/browser/permissions/permission_request_manager.h
@@ -136,6 +136,8 @@
   void WebContentsDestroyed() override;
 
   // PermissionPrompt::Delegate:
+  const std::vector<PermissionRequest*>& Requests() override;
+  const std::vector<bool>& AcceptStates() override;
   void ToggleAccept(int request_index, bool new_value) override;
   void TogglePersist(bool new_value) override;
   void Accept() override;
diff --git a/chrome/browser/resources/md_bookmarks/folder_node.html b/chrome/browser/resources/md_bookmarks/folder_node.html
index 9f87024..cf1629a 100644
--- a/chrome/browser/resources/md_bookmarks/folder_node.html
+++ b/chrome/browser/resources/md_bookmarks/folder_node.html
@@ -57,15 +57,18 @@
       #arrow {
         color: var(--secondary-text-color);
         margin: 0 8px;
+      }
+
+      #arrow iron-icon {
         transform: rotate(-90deg);
         transition: transform 150ms;
       }
 
-      :host-context([dir='rtl']) #arrow {
+      :host-context([dir='rtl']) #arrow iron-icon {
         transform: rotate(90deg);
       }
 
-      #arrow[is-open] {
+      #arrow iron-icon[is-open] {
         transform: initial;
       }
 
@@ -80,9 +83,9 @@
         hidden="[[isRootFolder_(depth)]]">
       <template is="dom-if" if="[[hasChildFolder_(item_.children)]]">
         <button is="paper-icon-button-light" id="arrow"
-            is-open$="[[!isClosed_]]" on-tap="toggleFolder_"
-            on-mousedown="preventDefault_" tabindex="-1">
-          <iron-icon icon="cr:arrow-drop-down"></iron-icon>
+            on-tap="toggleFolder_" on-mousedown="preventDefault_" tabindex="-1">
+          <iron-icon icon="cr:arrow-drop-down" is-open$="[[!isClosed_]]">
+          </iron-icon>
         </button>
       </template>
       <div id="folder-label" class="v-centered">
diff --git a/chrome/browser/resources/md_bookmarks/folder_node.js b/chrome/browser/resources/md_bookmarks/folder_node.js
index 4e25e715..12654b4 100644
--- a/chrome/browser/resources/md_bookmarks/folder_node.js
+++ b/chrome/browser/resources/md_bookmarks/folder_node.js
@@ -83,19 +83,26 @@
    * @param {!Event} e
    */
   onKeydown_: function(e) {
-    var direction = 0;
+    var yDirection = 0;
+    var xDirection = 0;
     var handled = true;
-    // TODO(calamity): Handle left/right arrow keys.
     if (e.key == 'ArrowUp') {
-      direction = -1;
+      yDirection = -1;
     } else if (e.key == 'ArrowDown') {
-      direction = 1;
+      yDirection = 1;
+    } else if (e.key == 'ArrowLeft') {
+      xDirection = -1;
+    } else if (e.key == 'ArrowRight') {
+      xDirection = 1;
     } else {
       handled = false;
     }
 
-    if (direction)
-      this.changeKeyboardSelection_(direction, this.root.activeElement);
+    if (this.getComputedStyleValue('direction') == 'rtl')
+      xDirection *= -1;
+
+    this.changeKeyboardSelection_(
+        xDirection, yDirection, this.root.activeElement);
 
     if (!handled)
       return;
@@ -106,17 +113,45 @@
 
   /**
    * @private
-   * @param {number} direction
+   * @param {number} xDirection
+   * @param {number} yDirection
    * @param {!HTMLElement} currentFocus
    */
-  changeKeyboardSelection_: function(direction, currentFocus) {
+  changeKeyboardSelection_: function(xDirection, yDirection, currentFocus) {
     var newFocusFolderNode = null;
     var isChildFolderNodeFocused =
         currentFocus.tagName == 'BOOKMARKS-FOLDER-NODE';
-    var reverse = direction == -1;
+
+    if (xDirection == 1) {
+      // The right arrow opens a folder if closed and goes to the first child
+      // otherwise.
+      if (this.hasChildFolder_()) {
+        if (this.isClosed_) {
+          this.dispatch(
+              bookmarks.actions.changeFolderOpen(this.item_.id, true));
+        } else {
+          yDirection = 1;
+        }
+      }
+    } else if (xDirection == -1) {
+      // The left arrow closes a folder if open and goes to the parent
+      // otherwise.
+      if (this.hasChildFolder_() && !this.isClosed_) {
+        this.dispatch(bookmarks.actions.changeFolderOpen(this.item_.id, false));
+      } else {
+        var parentFolderNode = this.getParentFolderNode_();
+        if (parentFolderNode.itemId != ROOT_NODE_ID) {
+          parentFolderNode.selectFolder_();
+          parentFolderNode.getFocusTarget().focus();
+        }
+      }
+    }
+
+    if (!yDirection)
+      return;
 
     // The current node's successor is its first child when open.
-    if (!isChildFolderNodeFocused && !reverse && !this.isClosed_) {
+    if (!isChildFolderNodeFocused && yDirection == 1 && !this.isClosed_) {
       var children = this.getChildFolderNodes_();
       if (children.length)
         newFocusFolderNode = children[0];
@@ -126,19 +161,20 @@
       // Get the next child folder node if a child is focused.
       if (!newFocusFolderNode) {
         newFocusFolderNode = this.getNextChild_(
-            reverse,
+            yDirection == -1,
             /** @type {!BookmarksFolderNodeElement} */ (currentFocus));
       }
 
       // The first child's predecessor is this node.
-      if (!newFocusFolderNode && reverse)
+      if (!newFocusFolderNode && yDirection == -1)
         newFocusFolderNode = this;
     }
 
     // If there is no newly focused node, allow the parent to handle the change.
     if (!newFocusFolderNode) {
       if (this.itemId != ROOT_NODE_ID)
-        this.getParentFolderNode_().changeKeyboardSelection_(direction, this);
+        this.getParentFolderNode_().changeKeyboardSelection_(
+            0, yDirection, this);
 
       return;
     }
diff --git a/chrome/browser/resources/settings/android_apps_page/android_apps_browser_proxy.js b/chrome/browser/resources/settings/android_apps_page/android_apps_browser_proxy.js
index 1a2e0be7..0c5c3d5 100644
--- a/chrome/browser/resources/settings/android_apps_page/android_apps_browser_proxy.js
+++ b/chrome/browser/resources/settings/android_apps_page/android_apps_browser_proxy.js
@@ -8,7 +8,13 @@
  */
 
 /**
- * @typedef {{appReady: boolean}}
+ * Type definition of AndroidAppsInfo entry. |playStoreEnabled| indicates that
+ * Play Store is enabled. |settingsAppAvailable| indicates that Android settings
+ * app is registered in the system.
+ * @typedef {{
+ *   playStoreEnabled: boolean,
+ *   settingsAppAvailable: boolean,
+ * }}
  * @see chrome/browser/ui/webui/settings/chromeos/android_apps_handler.cc
  */
 var AndroidAppsInfo;
diff --git a/chrome/browser/resources/settings/android_apps_page/android_apps_page.html b/chrome/browser/resources/settings/android_apps_page/android_apps_page.html
index 2d50c6c..a655bba6 100644
--- a/chrome/browser/resources/settings/android_apps_page/android_apps_page.html
+++ b/chrome/browser/resources/settings/android_apps_page/android_apps_page.html
@@ -30,13 +30,13 @@
           <cr-policy-pref-indicator pref="[[prefs.arc.enabled]]"
               icon-aria-label="$i18n{androidAppsPageTitle}">
           </cr-policy-pref-indicator>
-          <template is="dom-if" if="[[androidAppsInfo_.appReady]]">
+          <template is="dom-if" if="[[androidAppsInfo_.playStoreEnabled]]">
             <button class="subpage-arrow" is="paper-icon-button-light"
                 aria-label="$i18n{androidAppsPageTitle}"
                 aria-describedby="secondaryText">
             </button>
           </template>
-          <template is="dom-if" if="[[!androidAppsInfo_.appReady]]">
+          <template is="dom-if" if="[[!androidAppsInfo_.playStoreEnabled]]">
             <div class="separator"></div>
             <paper-button id="enable" class="secondary-button"
                 on-tap="onEnableTap_"
diff --git a/chrome/browser/resources/settings/android_apps_page/android_apps_page.js b/chrome/browser/resources/settings/android_apps_page/android_apps_page.js
index 8617317..e5f9cba6 100644
--- a/chrome/browser/resources/settings/android_apps_page/android_apps_page.js
+++ b/chrome/browser/resources/settings/android_apps_page/android_apps_page.js
@@ -38,17 +38,26 @@
   /** @private {?settings.AndroidAppsBrowserProxy} */
   browserProxy_: null,
 
+  /** @private {?WebUIListener} */
+  listener_: null,
+
   /** @override */
   created: function() {
     this.browserProxy_ = settings.AndroidAppsBrowserProxyImpl.getInstance();
   },
 
   /** @override */
-  ready: function() {
-    cr.addWebUIListener(
+  attached: function() {
+    this.listener_ = cr.addWebUIListener(
         'android-apps-info-update', this.androidAppsInfoUpdate_.bind(this));
     this.browserProxy_.requestAndroidAppsInfo();
   },
+
+  /** @override */
+  detached: function() {
+    cr.removeWebUIListener(this.listener_);
+  },
+
   /**
    * @param {AndroidAppsInfo} info
    * @private
@@ -68,7 +77,7 @@
 
   /** @private */
   onSubpageTap_: function() {
-    if (this.androidAppsInfo_.appReady)
+    if (this.androidAppsInfo_.playStoreEnabled)
       settings.navigateTo(settings.Route.ANDROID_APPS_DETAILS);
   },
 });
diff --git a/chrome/browser/resources/settings/android_apps_page/android_apps_subpage.html b/chrome/browser/resources/settings/android_apps_page/android_apps_subpage.html
index 8d48895..37e139f 100644
--- a/chrome/browser/resources/settings/android_apps_page/android_apps_subpage.html
+++ b/chrome/browser/resources/settings/android_apps_page/android_apps_subpage.html
@@ -15,7 +15,7 @@
     <div id="manageApps" class="settings-box first"
         on-keydown="onManageAndroidAppsKeydown_"
         on-tap="onManageAndroidAppsTap_" actionable
-        hidden="[[!androidAppsInfo_.appReady]]">
+        hidden="[[!androidAppsInfo.settingsAppAvailable]]">
       <div class="start">
         <div>$i18n{androidAppsManageApps}</div>
       </div>
diff --git a/chrome/browser/resources/settings/android_apps_page/android_apps_subpage.js b/chrome/browser/resources/settings/android_apps_page/android_apps_subpage.js
index 9dae8ffd..bb987f74 100644
--- a/chrome/browser/resources/settings/android_apps_page/android_apps_subpage.js
+++ b/chrome/browser/resources/settings/android_apps_page/android_apps_subpage.js
@@ -17,7 +17,10 @@
     prefs: Object,
 
     /** @private {!AndroidAppsInfo|undefined} */
-    androidAppsInfo: Object,
+    androidAppsInfo: {
+      type: Object,
+      observer: 'onAndroidAppsInfoUpdate_',
+    },
 
     /** @private */
     dialogBody_: {
@@ -39,6 +42,14 @@
   },
 
   /**
+   * @private
+   */
+  onAndroidAppsInfoUpdate_: function() {
+    if (!this.androidAppsInfo.playStoreEnabled)
+      settings.navigateToPreviousRoute();
+  },
+
+  /**
    * @param {Event} event
    * @private
    */
diff --git a/chrome/browser/ui/android/infobars/translate_compact_infobar.cc b/chrome/browser/ui/android/infobars/translate_compact_infobar.cc
index 0c0cec0f..94a729f 100644
--- a/chrome/browser/ui/android/infobars/translate_compact_infobar.cc
+++ b/chrome/browser/ui/android/infobars/translate_compact_infobar.cc
@@ -63,12 +63,21 @@
 
   // TODO(ramyasharma): Handle other button clicks.
   translate::TranslateInfoBarDelegate* delegate = GetDelegate();
-  if (action == InfoBarAndroid::ACTION_TRANSLATE)
+  if (action == InfoBarAndroid::ACTION_TRANSLATE) {
     delegate->Translate();
-  else if (action == InfoBarAndroid::ACTION_TRANSLATE_SHOW_ORIGINAL)
+    if (!delegate->ShouldAlwaysTranslate() &&
+        delegate->ShouldAutoAlwaysTranslate()) {
+      JNIEnv* env = base::android::AttachCurrentThread();
+      Java_TranslateCompactInfoBar_setAutoAlwaysTranslate(env,
+                                                          GetJavaInfoBar());
+    }
+  } else if (action == InfoBarAndroid::ACTION_TRANSLATE_SHOW_ORIGINAL) {
     delegate->RevertTranslation();
-  else
+  } else if (action == InfoBarAndroid::ACTION_CANCEL) {
+    delegate->TranslationDeclined();
+  } else {
     DCHECK_EQ(InfoBarAndroid::ACTION_NONE, action);
+  }
 }
 
 void TranslateCompactInfoBar::SetJavaInfoBar(
@@ -136,6 +145,11 @@
                                                 error_type);
 }
 
+bool TranslateCompactInfoBar::ShouldAutoAlwaysTranslate() {
+  translate::TranslateInfoBarDelegate* delegate = GetDelegate();
+  return delegate->ShouldAutoAlwaysTranslate();
+}
+
 translate::TranslateInfoBarDelegate* TranslateCompactInfoBar::GetDelegate() {
   return delegate()->AsTranslateInfoBarDelegate();
 }
diff --git a/chrome/browser/ui/android/infobars/translate_compact_infobar.h b/chrome/browser/ui/android/infobars/translate_compact_infobar.h
index 90ebd30..d186030b 100644
--- a/chrome/browser/ui/android/infobars/translate_compact_infobar.h
+++ b/chrome/browser/ui/android/infobars/translate_compact_infobar.h
@@ -36,6 +36,9 @@
                                 int option,
                                 jboolean value);
 
+  // Check whether we should automatically trigger "Always Translate".
+  bool ShouldAutoAlwaysTranslate();
+
   // ContentTranslateDriver::Observer implementation.
   void OnPageTranslated(const std::string& original_lang,
                         const std::string& translated_lang,
diff --git a/chrome/browser/ui/cocoa/permission_bubble/permission_bubble_cocoa.h b/chrome/browser/ui/cocoa/permission_bubble/permission_bubble_cocoa.h
index 54aa588f..775d550 100644
--- a/chrome/browser/ui/cocoa/permission_bubble/permission_bubble_cocoa.h
+++ b/chrome/browser/ui/cocoa/permission_bubble/permission_bubble_cocoa.h
@@ -24,8 +24,7 @@
   ~PermissionBubbleCocoa() override;
 
   // PermissionPrompt:
-  void Show(const std::vector<PermissionRequest*>& requests,
-            const std::vector<bool>& accept_state) override;
+  void Show() override;
   void Hide() override;
   void SetDelegate(Delegate* delegate) override;
   bool CanAcceptRequestUpdate() override;
diff --git a/chrome/browser/ui/cocoa/permission_bubble/permission_bubble_cocoa.mm b/chrome/browser/ui/cocoa/permission_bubble/permission_bubble_cocoa.mm
index fc032b00..6f644ad 100644
--- a/chrome/browser/ui/cocoa/permission_bubble/permission_bubble_cocoa.mm
+++ b/chrome/browser/ui/cocoa/permission_bubble/permission_bubble_cocoa.mm
@@ -17,9 +17,7 @@
 PermissionBubbleCocoa::~PermissionBubbleCocoa() {
 }
 
-void PermissionBubbleCocoa::Show(
-    const std::vector<PermissionRequest*>& requests,
-    const std::vector<bool>& accept_state) {
+void PermissionBubbleCocoa::Show() {
   DCHECK(browser_);
 
   if (!bubbleController_) {
@@ -28,9 +26,7 @@
                                                      bridge:this];
   }
 
-  [bubbleController_ showWithDelegate:delegate_
-                          forRequests:requests
-                         acceptStates:accept_state];
+  [bubbleController_ showWithDelegate:delegate_];
 }
 
 void PermissionBubbleCocoa::Hide() {
diff --git a/chrome/browser/ui/cocoa/permission_bubble/permission_bubble_cocoa_browser_test.mm b/chrome/browser/ui/cocoa/permission_bubble/permission_bubble_cocoa_browser_test.mm
index de7d740..a2a7fe5 100644
--- a/chrome/browser/ui/cocoa/permission_bubble/permission_bubble_cocoa_browser_test.mm
+++ b/chrome/browser/ui/cocoa/permission_bubble/permission_bubble_cocoa_browser_test.mm
@@ -17,7 +17,7 @@
 IN_PROC_BROWSER_TEST_F(PermissionBubbleBrowserTest, HasLocationBarByDefault) {
   PermissionBubbleCocoa bubble(browser());
   bubble.SetDelegate(test_delegate());
-  bubble.Show(requests(), accept_states());
+  bubble.Show();
   EXPECT_TRUE([bubble.bubbleController_ hasVisibleLocationBar]);
   bubble.Hide();
 }
@@ -28,7 +28,7 @@
 
   PermissionBubbleCocoa bubble(browser());
   bubble.SetDelegate(test_delegate());
-  bubble.Show(requests(), accept_states());
+  bubble.Show();
   EXPECT_TRUE([bubble.bubbleController_ hasVisibleLocationBar]);
 
   FullscreenController* controller =
@@ -61,7 +61,7 @@
 
   PermissionBubbleCocoa bubble(browser());
   bubble.SetDelegate(test_delegate());
-  bubble.Show(requests(), accept_states());
+  bubble.Show();
   EXPECT_TRUE([bubble.bubbleController_ hasVisibleLocationBar]);
 
   FullscreenController* controller =
@@ -83,7 +83,7 @@
   Browser* app_browser = OpenExtensionAppWindow();
   PermissionBubbleCocoa bubble(app_browser);
   bubble.SetDelegate(test_delegate());
-  bubble.Show(requests(), accept_states());
+  bubble.Show();
   EXPECT_FALSE([bubble.bubbleController_ hasVisibleLocationBar]);
   bubble.Hide();
 }
@@ -94,7 +94,7 @@
                        DISABLED_KioskHasNoLocationBar) {
   PermissionBubbleCocoa bubble(browser());
   bubble.SetDelegate(test_delegate());
-  bubble.Show(requests(), accept_states());
+  bubble.Show();
   EXPECT_FALSE([bubble.bubbleController_ hasVisibleLocationBar]);
   bubble.Hide();
 }
diff --git a/chrome/browser/ui/cocoa/permission_bubble/permission_bubble_controller.h b/chrome/browser/ui/cocoa/permission_bubble/permission_bubble_controller.h
index 18bc0ef4..c12423b 100644
--- a/chrome/browser/ui/cocoa/permission_bubble/permission_bubble_controller.h
+++ b/chrome/browser/ui/cocoa/permission_bubble/permission_bubble_controller.h
@@ -16,7 +16,6 @@
 class LocationBarDecoration;
 @class MenuController;
 class PermissionBubbleCocoa;
-class PermissionRequest;
 
 @interface PermissionBubbleController
     : BaseBubbleController<NSTextViewDelegate> {
@@ -54,10 +53,8 @@
 + (bool)hasVisibleLocationBarForBrowser:(Browser*)browser;
 
 // Makes the bubble visible. The bubble will be populated with text retrieved
-// from |requests|. |delegate| will receive callbacks for user actions.
-- (void)showWithDelegate:(PermissionPrompt::Delegate*)delegate
-             forRequests:(const std::vector<PermissionRequest*>&)requests
-            acceptStates:(const std::vector<bool>&)acceptStates;
+// from |delegate|, which will also receive callbacks for user actions.
+- (void)showWithDelegate:(PermissionPrompt::Delegate*)delegate;
 
 // Will reposition the bubble based in case the anchor or parent should change.
 - (void)updateAnchorPosition;
diff --git a/chrome/browser/ui/cocoa/permission_bubble/permission_bubble_controller.mm b/chrome/browser/ui/cocoa/permission_bubble/permission_bubble_controller.mm
index e0b1589..80539cf 100644
--- a/chrome/browser/ui/cocoa/permission_bubble/permission_bubble_controller.mm
+++ b/chrome/browser/ui/cocoa/permission_bubble/permission_bubble_controller.mm
@@ -281,13 +281,13 @@
   [self setAnchorPoint:[self getExpectedAnchorPoint]];
 }
 
-- (void)showWithDelegate:(PermissionPrompt::Delegate*)delegate
-             forRequests:(const std::vector<PermissionRequest*>&)requests
-            acceptStates:(const std::vector<bool>&)acceptStates {
-  DCHECK(!requests.empty());
+- (void)showWithDelegate:(PermissionPrompt::Delegate*)delegate {
   DCHECK(delegate);
   delegate_ = delegate;
 
+  const std::vector<PermissionRequest*>& requests = delegate->Requests();
+  DCHECK(!requests.empty());
+
   NSView* contentView = [[self window] contentView];
   [contentView setSubviews:@[]];
 
@@ -323,10 +323,9 @@
 
     if (!singlePermission) {
       int index = it - requests.begin();
-      base::scoped_nsobject<NSView> menu(
-          [[self menuForRequest:(*it)
-                        atIndex:index
-                          allow:acceptStates[index] ? YES : NO] retain]);
+      base::scoped_nsobject<NSView> menu([[self
+          menuForRequest:(*it)atIndex:index
+                   allow:delegate->AcceptStates()[index] ? YES : NO] retain]);
       // Align vertically.  Horizontal alignment will be adjusted once the
       // widest permission is know.
       [PermissionBubbleController alignCenterOf:menu
diff --git a/chrome/browser/ui/cocoa/permission_bubble/permission_bubble_controller_unittest.mm b/chrome/browser/ui/cocoa/permission_bubble/permission_bubble_controller_unittest.mm
index b4fb315..8583736c 100644
--- a/chrome/browser/ui/cocoa/permission_bubble/permission_bubble_controller_unittest.mm
+++ b/chrome/browser/ui/cocoa/permission_bubble/permission_bubble_controller_unittest.mm
@@ -93,6 +93,12 @@
     CocoaProfileTest::TearDown();
   }
 
+  const std::vector<PermissionRequest*>& Requests() override {
+    return requests_;
+  }
+
+  const std::vector<bool>& AcceptStates() override { return accept_states_; }
+
   void AddRequest(const std::string& title) {
     std::unique_ptr<MockPermissionRequest> request =
         base::MakeUnique<MockPermissionRequest>(
@@ -192,9 +198,7 @@
 }
 
 TEST_F(PermissionBubbleControllerTest, ShowSinglePermission) {
-  [controller_ showWithDelegate:this
-                    forRequests:requests_
-                   acceptStates:accept_states_];
+  [controller_ showWithDelegate:this];
 
   EXPECT_TRUE(FindTextFieldWithString(kPermissionA));
   EXPECT_TRUE(FindButtonWithTitle(IDS_PERMISSION_ALLOW));
@@ -210,9 +214,7 @@
   accept_states_.push_back(true);  // B
   accept_states_.push_back(true);  // C
 
-  [controller_ showWithDelegate:this
-                    forRequests:requests_
-                   acceptStates:accept_states_];
+  [controller_ showWithDelegate:this];
 
   EXPECT_TRUE(FindTextFieldWithString(kPermissionA));
   EXPECT_TRUE(FindTextFieldWithString(kPermissionB));
@@ -229,9 +231,7 @@
   accept_states_.push_back(true);  // A
   accept_states_.push_back(true);  // B
 
-  [controller_ showWithDelegate:this
-                    forRequests:requests_
-                   acceptStates:accept_states_];
+  [controller_ showWithDelegate:this];
 
   // Test that all menus have 'Allow' visible.
   EXPECT_TRUE(FindMenuButtonWithTitle(IDS_PERMISSION_ALLOW));
@@ -248,9 +248,7 @@
   accept_states_.push_back(false);  // A
   accept_states_.push_back(false);  // B
 
-  [controller_ showWithDelegate:this
-                    forRequests:requests_
-                   acceptStates:accept_states_];
+  [controller_ showWithDelegate:this];
 
   // Test that all menus have 'Block' visible.
   EXPECT_TRUE(FindMenuButtonWithTitle(IDS_PERMISSION_DENY));
@@ -269,9 +267,7 @@
   accept_states_.push_back(false);  // B
   accept_states_.push_back(true);   // C
 
-  [controller_ showWithDelegate:this
-                    forRequests:requests_
-                   acceptStates:accept_states_];
+  [controller_ showWithDelegate:this];
 
   // Test that both 'allow' and 'deny' are visible.
   EXPECT_TRUE(FindMenuButtonWithTitle(IDS_PERMISSION_DENY));
@@ -288,27 +284,21 @@
   accept_states_.push_back(true);  // A
   accept_states_.push_back(true);  // B
 
-  [controller_ showWithDelegate:this
-                    forRequests:requests_
-                   acceptStates:accept_states_];
+  [controller_ showWithDelegate:this];
 
   EXPECT_CALL(*this, Accept()).Times(1);
   [FindButtonWithTitle(IDS_OK) performClick:nil];
 }
 
 TEST_F(PermissionBubbleControllerTest, Allow) {
-  [controller_ showWithDelegate:this
-                    forRequests:requests_
-                   acceptStates:accept_states_];
+  [controller_ showWithDelegate:this];
 
   EXPECT_CALL(*this, Accept()).Times(1);
   [FindButtonWithTitle(IDS_PERMISSION_ALLOW) performClick:nil];
 }
 
 TEST_F(PermissionBubbleControllerTest, Deny) {
-  [controller_ showWithDelegate:this
-                    forRequests:requests_
-                   acceptStates:accept_states_];
+  [controller_ showWithDelegate:this];
 
   EXPECT_CALL(*this, Deny()).Times(1);
   [FindButtonWithTitle(IDS_PERMISSION_DENY) performClick:nil];
@@ -320,9 +310,7 @@
   accept_states_.push_back(true);   // A
   accept_states_.push_back(false);  // B
 
-  [controller_ showWithDelegate:this
-                    forRequests:requests_
-                   acceptStates:accept_states_];
+  [controller_ showWithDelegate:this];
 
   EXPECT_CALL(*this, ToggleAccept(0, false)).Times(1);
   EXPECT_CALL(*this, ToggleAccept(1, true)).Times(1);
@@ -333,9 +321,7 @@
 }
 
 TEST_F(PermissionBubbleControllerTest, EscapeCloses) {
-  [controller_ showWithDelegate:this
-                    forRequests:requests_
-                   acceptStates:accept_states_];
+  [controller_ showWithDelegate:this];
 
   EXPECT_TRUE([[controller_ window] isVisible]);
   [[controller_ window]
@@ -345,9 +331,7 @@
 }
 
 TEST_F(PermissionBubbleControllerTest, EnterFullscreen) {
-  [controller_ showWithDelegate:this
-                    forRequests:requests_
-                   acceptStates:accept_states_];
+  [controller_ showWithDelegate:this];
 
   EXPECT_TRUE([[controller_ window] isVisible]);
 
@@ -360,9 +344,7 @@
 }
 
 TEST_F(PermissionBubbleControllerTest, ExitFullscreen) {
-  [controller_ showWithDelegate:this
-                    forRequests:requests_
-                   acceptStates:accept_states_];
+  [controller_ showWithDelegate:this];
 
   EXPECT_TRUE([[controller_ window] isVisible]);
 
diff --git a/chrome/browser/ui/permission_bubble/mock_permission_prompt.cc b/chrome/browser/ui/permission_bubble/mock_permission_prompt.cc
index 99d19de..2618143e 100644
--- a/chrome/browser/ui/permission_bubble/mock_permission_prompt.cc
+++ b/chrome/browser/ui/permission_bubble/mock_permission_prompt.cc
@@ -13,8 +13,7 @@
   Hide();
 }
 
-void MockPermissionPrompt::Show(const std::vector<PermissionRequest*>& requests,
-                                const std::vector<bool>& accept_state) {
+void MockPermissionPrompt::Show() {
   factory_->ShowView(this);
   factory_->show_count_++;
   factory_->requests_count_ = manager_->requests_.size();
diff --git a/chrome/browser/ui/permission_bubble/mock_permission_prompt.h b/chrome/browser/ui/permission_bubble/mock_permission_prompt.h
index 58bdd2fa..7ae6942 100644
--- a/chrome/browser/ui/permission_bubble/mock_permission_prompt.h
+++ b/chrome/browser/ui/permission_bubble/mock_permission_prompt.h
@@ -20,8 +20,7 @@
 
   // PermissionPrompt:
   void SetDelegate(Delegate* delegate) override {}
-  void Show(const std::vector<PermissionRequest*>& requests,
-            const std::vector<bool>& accept_state) override;
+  void Show() override;
   bool CanAcceptRequestUpdate() override;
   bool HidesAutomatically() override;
   void Hide() override;
diff --git a/chrome/browser/ui/permission_bubble/permission_bubble_browser_test_util.cc b/chrome/browser/ui/permission_bubble/permission_bubble_browser_test_util.cc
index fe6b7a0..19a2548 100644
--- a/chrome/browser/ui/permission_bubble/permission_bubble_browser_test_util.cc
+++ b/chrome/browser/ui/permission_bubble/permission_bubble_browser_test_util.cc
@@ -22,6 +22,17 @@
     : PermissionPrompt::Delegate() {
 }
 
+TestPermissionBubbleViewDelegate::~TestPermissionBubbleViewDelegate() {}
+
+const std::vector<PermissionRequest*>&
+TestPermissionBubbleViewDelegate::Requests() {
+  return requests_;
+}
+
+const std::vector<bool>& TestPermissionBubbleViewDelegate::AcceptStates() {
+  return accept_states_;
+}
+
 PermissionBubbleBrowserTest::PermissionBubbleBrowserTest() {
 }
 
@@ -35,6 +46,10 @@
   requests_.push_back(base::MakeUnique<MockPermissionRequest>(
       "Request 1", l10n_util::GetStringUTF8(IDS_PERMISSION_ALLOW),
       l10n_util::GetStringUTF8(IDS_PERMISSION_DENY)));
+
+  std::vector<PermissionRequest*> raw_requests;
+  raw_requests.push_back(requests_[0].get());
+  test_delegate_.set_requests(raw_requests);
 }
 
 Browser* PermissionBubbleBrowserTest::OpenExtensionAppWindow() {
@@ -56,13 +71,6 @@
   return app_browser;
 }
 
-std::vector<PermissionRequest*> PermissionBubbleBrowserTest::requests() {
-  std::vector<PermissionRequest*> result;
-  for (const auto& request : requests_)
-    result.push_back(request.get());
-  return result;
-}
-
 PermissionBubbleKioskBrowserTest::PermissionBubbleKioskBrowserTest() {
 }
 
diff --git a/chrome/browser/ui/permission_bubble/permission_bubble_browser_test_util.h b/chrome/browser/ui/permission_bubble/permission_bubble_browser_test_util.h
index 66a8295..76a0a9b 100644
--- a/chrome/browser/ui/permission_bubble/permission_bubble_browser_test_util.h
+++ b/chrome/browser/ui/permission_bubble/permission_bubble_browser_test_util.h
@@ -21,6 +21,10 @@
 class TestPermissionBubbleViewDelegate : public PermissionPrompt::Delegate {
  public:
   TestPermissionBubbleViewDelegate();
+  ~TestPermissionBubbleViewDelegate() override;
+
+  const std::vector<PermissionRequest*>& Requests() override;
+  const std::vector<bool>& AcceptStates() override;
 
   void ToggleAccept(int, bool) override {}
   void TogglePersist(bool) override {}
@@ -28,7 +32,14 @@
   void Deny() override {}
   void Closing() override {}
 
+  void set_requests(std::vector<PermissionRequest*> requests) {
+    requests_ = requests;
+  }
+
  private:
+  std::vector<PermissionRequest*> requests_;
+  std::vector<bool> accept_states_;
+
   DISALLOW_COPY_AND_ASSIGN(TestPermissionBubbleViewDelegate);
 };
 
@@ -45,8 +56,6 @@
   // Opens an app window, and returns the associated browser.
   Browser* OpenExtensionAppWindow();
 
-  std::vector<PermissionRequest*> requests();
-  std::vector<bool> accept_states() { return accept_states_; }
   PermissionPrompt::Delegate* test_delegate() { return &test_delegate_; }
 
  private:
diff --git a/chrome/browser/ui/permission_bubble/permission_prompt.h b/chrome/browser/ui/permission_bubble/permission_prompt.h
index 7f6f770..6e172b4 100644
--- a/chrome/browser/ui/permission_bubble/permission_prompt.h
+++ b/chrome/browser/ui/permission_bubble/permission_prompt.h
@@ -29,6 +29,11 @@
    public:
     virtual ~Delegate() {}
 
+    // These pointers should not be stored as the actual request objects may be
+    // deleted upon navigation and so on.
+    virtual const std::vector<PermissionRequest*>& Requests() = 0;
+    virtual const std::vector<bool>& AcceptStates() = 0;
+
     virtual void ToggleAccept(int index, bool new_value) = 0;
     virtual void TogglePersist(bool new_value) = 0;
     virtual void Accept() = 0;
@@ -48,14 +53,9 @@
   // Sets the delegate which will receive UI events forwarded from the prompt.
   virtual void SetDelegate(Delegate* delegate) = 0;
 
-  // Causes the request UI to show up with the given contents. This method may
-  // be called with mostly-identical contents to the existing contents. This can
-  // happen, for instance, if a new permission is requested and
-  // CanAcceptRequestUpdate() is true.
-  // Important: the view must not store any of the request objects it receives
-  // in this call.
-  virtual void Show(const std::vector<PermissionRequest*>& requests,
-                    const std::vector<bool>& accept_state) = 0;
+  // Show a prompt with the requests from the delegate. This will only be called
+  // if there is no prompt showing.
+  virtual void Show() = 0;
 
   // Returns true if the view can accept a new Show() command to coalesce
   // requests. Currently the policy is that this should return true if the view
diff --git a/chrome/browser/ui/views/payments/editor_view_controller.cc b/chrome/browser/ui/views/payments/editor_view_controller.cc
index 44ac42a6..5252645 100644
--- a/chrome/browser/ui/views/payments/editor_view_controller.cc
+++ b/chrome/browser/ui/views/payments/editor_view_controller.cc
@@ -138,28 +138,8 @@
   content_view->AddChildView(CreateEditorView().release());
 }
 
-// Adds the "required fields" label in disabled text, to obtain this result.
-// +---------------------------------------------------------+
-// | "* indicates required fields"           | CANCEL | DONE |
-// +---------------------------------------------------------+
-std::unique_ptr<views::View> EditorViewController::CreateExtraFooterView() {
-  std::unique_ptr<views::View> content_view = base::MakeUnique<views::View>();
-
-  views::BoxLayout* layout =
-      new views::BoxLayout(views::BoxLayout::kHorizontal, 0, 0, 0);
-  layout->set_main_axis_alignment(views::BoxLayout::MAIN_AXIS_ALIGNMENT_START);
-  layout->set_cross_axis_alignment(
-      views::BoxLayout::CROSS_AXIS_ALIGNMENT_START);
-  content_view->SetLayoutManager(layout);
-
-  // Adds the "* indicates a required field" label in "disabled" grey text.
-  std::unique_ptr<views::Label> label = base::MakeUnique<views::Label>(
-      l10n_util::GetStringUTF16(IDS_PAYMENTS_REQUIRED_FIELD_MESSAGE));
-  label->SetDisabledColor(label->GetNativeTheme()->GetSystemColor(
-      ui::NativeTheme::kColorId_LabelDisabledColor));
-  label->SetEnabled(false);
-  content_view->AddChildView(label.release());
-  return content_view;
+base::string16 EditorViewController::GetSecondaryButtonLabel() {
+  return l10n_util::GetStringUTF16(IDS_PAYMENTS_CANCEL_PAYMENT);
 }
 
 void EditorViewController::UpdateEditorView() {
@@ -281,12 +261,25 @@
                      kFieldExtraViewHorizontalPadding - long_extra_view_width;
   columns_long->AddPaddingColumn(0, long_padding);
 
+  for (const auto& field : GetFieldDefinitions())
+    CreateInputField(editor_layout.get(), field);
+
+  // Adds the "* indicates a required field" label in "disabled" grey text.
+  std::unique_ptr<views::Label> required_field = base::MakeUnique<views::Label>(
+      l10n_util::GetStringUTF16(IDS_PAYMENTS_REQUIRED_FIELD_MESSAGE));
+  required_field->SetDisabledColor(
+      required_field->GetNativeTheme()->GetSystemColor(
+          ui::NativeTheme::kColorId_LabelDisabledColor));
+  required_field->SetEnabled(false);
+
+  views::ColumnSet* required_field_columns = editor_layout->AddColumnSet(2);
+  required_field_columns->AddColumn(views::GridLayout::LEADING,
+                                    views::GridLayout::CENTER, 1,
+                                    views::GridLayout::USE_PREF, 0, 0);
+  editor_layout->StartRow(0, 2);
+  editor_layout->AddView(required_field.release());
+
   editor_view->SetLayoutManager(editor_layout.release());
-  for (const auto& field : GetFieldDefinitions()) {
-    CreateInputField(
-        static_cast<views::GridLayout*>(editor_view->GetLayoutManager()),
-        field);
-  }
 
   return editor_view;
 }
diff --git a/chrome/browser/ui/views/payments/editor_view_controller.h b/chrome/browser/ui/views/payments/editor_view_controller.h
index 0246bfdf..da5410f 100644
--- a/chrome/browser/ui/views/payments/editor_view_controller.h
+++ b/chrome/browser/ui/views/payments/editor_view_controller.h
@@ -132,8 +132,8 @@
 
   // PaymentRequestSheetController;
   std::unique_ptr<views::Button> CreatePrimaryButton() override;
+  base::string16 GetSecondaryButtonLabel() override;
   void FillContentView(views::View* content_view) override;
-  std::unique_ptr<views::View> CreateExtraFooterView() override;
 
   // views::ComboboxListener:
   void OnPerformAction(views::Combobox* combobox) override;
diff --git a/chrome/browser/ui/views/payments/order_summary_view_controller.cc b/chrome/browser/ui/views/payments/order_summary_view_controller.cc
index bc613c30..b3b3526 100644
--- a/chrome/browser/ui/views/payments/order_summary_view_controller.cc
+++ b/chrome/browser/ui/views/payments/order_summary_view_controller.cc
@@ -134,6 +134,7 @@
       views::BoxLayout::CROSS_AXIS_ALIGNMENT_STRETCH);
   content_view->SetLayoutManager(layout);
 
+  bool is_mixed_currency = spec()->IsMixedCurrency();
   // Set the ID for the first few line items labels, for testing.
   const std::vector<DialogViewID> line_items{
       DialogViewID::ORDER_SUMMARY_LINE_ITEM_1,
@@ -142,20 +143,30 @@
   for (size_t i = 0; i < spec()->details().display_items.size(); i++) {
     DialogViewID view_id =
         i < line_items.size() ? line_items[i] : DialogViewID::VIEW_ID_NONE;
+    base::string16 value_string;
+    if (is_mixed_currency) {
+      value_string = l10n_util::GetStringFUTF16(
+          IDS_PAYMENT_REQUEST_ORDER_SUMMARY_SHEET_TOTAL_FORMAT,
+          base::UTF8ToUTF16(
+              spec()->details().display_items[i]->amount->currency),
+          spec()->GetFormattedCurrencyAmount(
+              spec()->details().display_items[i]->amount));
+    } else {
+      value_string = spec()->GetFormattedCurrencyAmount(
+          spec()->details().display_items[i]->amount);
+    }
+
     content_view->AddChildView(
         CreateLineItemView(
             base::UTF8ToUTF16(spec()->details().display_items[i]->label),
-            spec()->GetFormattedCurrencyAmount(
-                spec()->details().display_items[i]->amount->value),
-            false, view_id)
+            value_string, false, view_id)
             .release());
   }
 
   base::string16 total_label_value = l10n_util::GetStringFUTF16(
       IDS_PAYMENT_REQUEST_ORDER_SUMMARY_SHEET_TOTAL_FORMAT,
       base::UTF8ToUTF16(spec()->details().total->amount->currency),
-      spec()->GetFormattedCurrencyAmount(
-          spec()->details().total->amount->value));
+      spec()->GetFormattedCurrencyAmount(spec()->details().total->amount));
 
   content_view->AddChildView(
       CreateLineItemView(base::UTF8ToUTF16(spec()->details().total->label),
diff --git a/chrome/browser/ui/views/payments/payment_sheet_view_controller.cc b/chrome/browser/ui/views/payments/payment_sheet_view_controller.cc
index 729c55e..6f5a599 100644
--- a/chrome/browser/ui/views/payments/payment_sheet_view_controller.cc
+++ b/chrome/browser/ui/views/payments/payment_sheet_view_controller.cc
@@ -576,6 +576,8 @@
 
   const std::vector<mojom::PaymentItemPtr>& items =
       spec()->details().display_items;
+
+  bool is_mixed_currency = spec()->IsMixedCurrency();
   // The inline items section contains the first 2 display items of the
   // request's details, followed by a label indicating "N more items..." if
   // there are more than 2 items in the details. The total label and amount
@@ -588,8 +590,18 @@
     summary->SetHorizontalAlignment(gfx::ALIGN_LEFT);
     layout->AddView(summary.release());
 
-    layout->AddView(new views::Label(
-        spec()->GetFormattedCurrencyAmount(items[i]->amount->value)));
+    base::string16 item_amount;
+    if (is_mixed_currency) {
+      // If the payment request has items in different currencies, always
+      // display the currency code.
+      item_amount = l10n_util::GetStringFUTF16(
+          IDS_PAYMENT_REQUEST_ORDER_SUMMARY_SHEET_TOTAL_FORMAT,
+          base::UTF8ToUTF16(spec()->GetFormattedCurrencyCode(items[i]->amount)),
+          spec()->GetFormattedCurrencyAmount(items[i]->amount));
+    } else {
+      item_amount = spec()->GetFormattedCurrencyAmount(items[i]->amount);
+    }
+    layout->AddView(new views::Label(item_amount));
   }
 
   int hidden_item_count = items.size() - kMaxNumberOfItemsShown;
@@ -612,9 +624,10 @@
   layout->AddView(
       CreateBoldLabel(l10n_util::GetStringFUTF16(
                           IDS_PAYMENT_REQUEST_ORDER_SUMMARY_SHEET_TOTAL_FORMAT,
-                          base::UTF8ToUTF16(spec()->GetFormattedCurrencyCode()),
+                          base::UTF8ToUTF16(spec()->GetFormattedCurrencyCode(
+                              spec()->details().total->amount)),
                           spec()->GetFormattedCurrencyAmount(
-                              spec()->details().total->amount->value)))
+                              spec()->details().total->amount)))
           .release());
 
   inline_summary->SetLayoutManager(layout.release());
@@ -887,10 +900,10 @@
           current_update_reason_ ==
                   PaymentRequestSpec::UpdateReason::SHIPPING_OPTION
               ? CreateCheckingSpinnerView()
-              : CreateShippingOptionLabel(selected_option,
-                                          spec()->GetFormattedCurrencyAmount(
-                                              selected_option->amount->value),
-                                          /*emphasize_label=*/false);
+              : CreateShippingOptionLabel(
+                    selected_option,
+                    spec()->GetFormattedCurrencyAmount(selected_option->amount),
+                    /*emphasize_label=*/false);
       return builder.Id(DialogViewID::PAYMENT_SHEET_SHIPPING_OPTION_SECTION)
           .CreateWithChevron(std::move(option_row_content), nullptr);
     } else {
diff --git a/chrome/browser/ui/views/payments/shipping_option_view_controller.cc b/chrome/browser/ui/views/payments/shipping_option_view_controller.cc
index b5e4299..1f78641 100644
--- a/chrome/browser/ui/views/payments/shipping_option_view_controller.cc
+++ b/chrome/browser/ui/views/payments/shipping_option_view_controller.cc
@@ -33,7 +33,7 @@
   std::unique_ptr<views::View> CreateContentView() override {
     return CreateShippingOptionLabel(
         shipping_option_,
-        spec()->GetFormattedCurrencyAmount(shipping_option_->amount->value),
+        spec()->GetFormattedCurrencyAmount(shipping_option_->amount),
         /*emphasize_label=*/true);
   }
 
diff --git a/chrome/browser/ui/views/permission_bubble/permission_prompt_impl.cc b/chrome/browser/ui/views/permission_bubble/permission_prompt_impl.cc
index f5f1cb28a..d01ab4c6 100644
--- a/chrome/browser/ui/views/permission_bubble/permission_prompt_impl.cc
+++ b/chrome/browser/ui/views/permission_bubble/permission_prompt_impl.cc
@@ -402,16 +402,15 @@
   delegate_ = delegate;
 }
 
-void PermissionPromptImpl::Show(const std::vector<PermissionRequest*>& requests,
-                                const std::vector<bool>& values) {
+void PermissionPromptImpl::Show() {
   DCHECK(browser_);
   DCHECK(browser_->window());
 
   if (bubble_delegate_)
     bubble_delegate_->CloseBubble();
 
-  bubble_delegate_ =
-      new PermissionsBubbleDialogDelegateView(this, requests, values);
+  bubble_delegate_ = new PermissionsBubbleDialogDelegateView(
+      this, delegate_->Requests(), delegate_->AcceptStates());
 
   // Set |parent_window| because some valid anchors can become hidden.
   bubble_delegate_->set_parent_window(
diff --git a/chrome/browser/ui/views/permission_bubble/permission_prompt_impl.h b/chrome/browser/ui/views/permission_bubble/permission_prompt_impl.h
index 710b2a2..a6c017a1 100644
--- a/chrome/browser/ui/views/permission_bubble/permission_prompt_impl.h
+++ b/chrome/browser/ui/views/permission_bubble/permission_prompt_impl.h
@@ -29,8 +29,7 @@
 
   // PermissionPrompt:
   void SetDelegate(Delegate* delegate) override;
-  void Show(const std::vector<PermissionRequest*>& requests,
-            const std::vector<bool>& accept_state) override;
+  void Show() override;
   bool CanAcceptRequestUpdate() override;
   bool HidesAutomatically() override;
   void Hide() override;
diff --git a/chrome/browser/ui/views/tabs/tab.cc b/chrome/browser/ui/views/tabs/tab.cc
index 9473bf31..d85baf732 100644
--- a/chrome/browser/ui/views/tabs/tab.cc
+++ b/chrome/browser/ui/views/tabs/tab.cc
@@ -1148,11 +1148,11 @@
                       inactive_color, stroke_color);
   }
 
-  canvas->sk_canvas()->PlaybackPaintRecord(cache.fill_record);
+  canvas->sk_canvas()->drawPicture(cache.fill_record);
   gfx::ScopedCanvas scoped_canvas(clip ? canvas : nullptr);
   if (clip)
     canvas->sk_canvas()->clipPath(*clip, SkClipOp::kDifference, true);
-  canvas->sk_canvas()->PlaybackPaintRecord(cache.stroke_record);
+  canvas->sk_canvas()->drawPicture(cache.stroke_record);
 }
 
 void Tab::PaintTabBackgroundFill(gfx::Canvas* canvas,
diff --git a/chrome/browser/ui/webui/settings/chromeos/android_apps_handler.cc b/chrome/browser/ui/webui/settings/chromeos/android_apps_handler.cc
index 099654c..78eacae 100644
--- a/chrome/browser/ui/webui/settings/chromeos/android_apps_handler.cc
+++ b/chrome/browser/ui/webui/settings/chromeos/android_apps_handler.cc
@@ -14,7 +14,10 @@
 namespace settings {
 
 AndroidAppsHandler::AndroidAppsHandler(Profile* profile)
-    : arc_prefs_observer_(this), profile_(profile), weak_ptr_factory_(this) {}
+    : arc_prefs_observer_(this),
+      arc_session_manager_observer_(this),
+      profile_(profile),
+      weak_ptr_factory_(this) {}
 
 AndroidAppsHandler::~AndroidAppsHandler() {}
 
@@ -31,12 +34,16 @@
 
 void AndroidAppsHandler::OnJavascriptAllowed() {
   ArcAppListPrefs* arc_prefs = ArcAppListPrefs::Get(profile_);
-  if (arc_prefs)
+  if (arc_prefs) {
     arc_prefs_observer_.Add(arc_prefs);
+    // arc::ArcSessionManager is assosiated with primary profile.
+    arc_session_manager_observer_.Add(arc::ArcSessionManager::Get());
+  }
 }
 
 void AndroidAppsHandler::OnJavascriptDisallowed() {
   arc_prefs_observer_.RemoveAll();
+  arc_session_manager_observer_.RemoveAll();
 }
 
 void AndroidAppsHandler::OnAppRegistered(
@@ -49,27 +56,24 @@
   OnAppChanged(app_id);
 }
 
-void AndroidAppsHandler::OnAppReadyChanged(const std::string& app_id,
-                                           bool ready) {
-  OnAppChanged(app_id);
-}
-
 void AndroidAppsHandler::OnAppChanged(const std::string& app_id) {
   if (app_id != arc::kSettingsAppId)
     return;
   SendAndroidAppsInfo();
 }
 
+void AndroidAppsHandler::OnArcPlayStoreEnabledChanged(bool enabled) {
+  SendAndroidAppsInfo();
+}
+
 std::unique_ptr<base::DictionaryValue>
 AndroidAppsHandler::BuildAndroidAppsInfo() {
   std::unique_ptr<base::DictionaryValue> info(new base::DictionaryValue);
-  bool app_ready = false;
-  if (arc::IsArcPlayStoreEnabledForProfile(profile_)) {
-    std::unique_ptr<ArcAppListPrefs::AppInfo> app_info =
-        ArcAppListPrefs::Get(profile_)->GetApp(arc::kSettingsAppId);
-    app_ready = app_info && app_info->ready;
-  }
-  info->SetBoolean("appReady", app_ready);
+  info->SetBoolean("playStoreEnabled",
+                   arc::IsArcPlayStoreEnabledForProfile(profile_));
+  info->SetBoolean(
+      "settingsAppAvailable",
+      ArcAppListPrefs::Get(profile_)->IsRegistered(arc::kSettingsAppId));
   return info;
 }
 
diff --git a/chrome/browser/ui/webui/settings/chromeos/android_apps_handler.h b/chrome/browser/ui/webui/settings/chromeos/android_apps_handler.h
index 7180bb1..62a530c 100644
--- a/chrome/browser/ui/webui/settings/chromeos/android_apps_handler.h
+++ b/chrome/browser/ui/webui/settings/chromeos/android_apps_handler.h
@@ -10,6 +10,7 @@
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
 #include "base/scoped_observer.h"
+#include "chrome/browser/chromeos/arc/arc_session_manager.h"
 #include "chrome/browser/ui/app_list/arc/arc_app_list_prefs.h"
 #include "chrome/browser/ui/webui/settings/settings_page_ui_handler.h"
 
@@ -23,7 +24,8 @@
 namespace settings {
 
 class AndroidAppsHandler : public ::settings::SettingsPageUIHandler,
-                           public ArcAppListPrefs::Observer {
+                           public ArcAppListPrefs::Observer,
+                           public arc::ArcSessionManager::Observer {
  public:
   explicit AndroidAppsHandler(Profile* profile);
   ~AndroidAppsHandler() override;
@@ -34,11 +36,13 @@
   void OnJavascriptDisallowed() override;
 
   // ArcAppListPrefs::Observer
-  void OnAppReadyChanged(const std::string& app_id, bool ready) override;
   void OnAppRemoved(const std::string& app_id) override;
   void OnAppRegistered(const std::string& app_id,
                        const ArcAppListPrefs::AppInfo& app_info) override;
 
+  // arc::ArcSessionManager::Observer:
+  void OnArcPlayStoreEnabledChanged(bool enabled) override;
+
  private:
   std::unique_ptr<base::DictionaryValue> BuildAndroidAppsInfo();
   void OnAppChanged(const std::string& app_id);
@@ -48,6 +52,8 @@
 
   ScopedObserver<ArcAppListPrefs, ArcAppListPrefs::Observer>
       arc_prefs_observer_;
+  ScopedObserver<arc::ArcSessionManager, arc::ArcSessionManager::Observer>
+      arc_session_manager_observer_;
   Profile* profile_;  // unowned
   base::WeakPtrFactory<AndroidAppsHandler> weak_ptr_factory_;
 
diff --git a/chrome/test/data/webui/md_bookmarks/md_bookmarks_focus_test.js b/chrome/test/data/webui/md_bookmarks/md_bookmarks_focus_test.js
index e70c1568..e1ca42b 100644
--- a/chrome/test/data/webui/md_bookmarks/md_bookmarks_focus_test.js
+++ b/chrome/test/data/webui/md_bookmarks/md_bookmarks_focus_test.js
@@ -97,6 +97,12 @@
       keydown('1', 'ArrowDown');
 
       assertDeepEquals(bookmarks.actions.selectFolder('2'), store.lastAction);
+      store.data.selectedFolder = '2';
+      store.notifyObservers();
+
+      assertEquals('', getFolderNode('1').$.container.getAttribute('tabindex'));
+      assertEquals(
+          '0', getFolderNode('2').$.container.getAttribute('tabindex'));
       assertFocused('1', '2');
 
       // Move down past closed folders.
@@ -124,6 +130,54 @@
       keydown('1', 'ArrowUp');
       assertDeepEquals(null, store.lastAction);
     });
+
+    test('keyboard left/right', function() {
+      store.data.closedFolders = new Set('2');
+      store.notifyObservers();
+
+      // Give keyboard focus to the first item.
+      getFolderNode('1').$.container.focus();
+
+      // Pressing right descends into first child.
+      keydown('1', 'ArrowRight');
+      assertDeepEquals(bookmarks.actions.selectFolder('2'), store.lastAction);
+
+      // Pressing right on a closed folder opens that folder
+      keydown('2', 'ArrowRight');
+      assertDeepEquals(
+          bookmarks.actions.changeFolderOpen('2', true), store.lastAction);
+
+      // Pressing right again descends into first child.
+      keydown('2', 'ArrowRight');
+      assertDeepEquals(bookmarks.actions.selectFolder('3'), store.lastAction);
+
+      // Pressing right on a folder with no children does nothing.
+      store.resetLastAction();
+      keydown('3', 'ArrowRight');
+      assertDeepEquals(null, store.lastAction);
+
+      // Pressing left on a folder with no children ascends to parent.
+      keydown('3', 'ArrowDown');
+      keydown('4', 'ArrowLeft');
+      assertDeepEquals(bookmarks.actions.selectFolder('2'), store.lastAction);
+
+      // Pressing left again closes the parent.
+      keydown('2', 'ArrowLeft');
+      assertDeepEquals(
+          bookmarks.actions.changeFolderOpen('2', false), store.lastAction);
+
+      // RTL flips left and right.
+      document.body.style.direction = 'rtl';
+      keydown('2', 'ArrowLeft');
+      assertDeepEquals(
+          bookmarks.actions.changeFolderOpen('2', true), store.lastAction);
+
+      keydown('2', 'ArrowRight');
+      assertDeepEquals(
+          bookmarks.actions.changeFolderOpen('2', false), store.lastAction);
+
+      document.body.style.direction = 'ltr';
+    });
   });
 
   mocha.run();
diff --git a/chrome/test/data/webui/settings/android_apps_page_test.js b/chrome/test/data/webui/settings/android_apps_page_test.js
index f5e2dac..64cf36d 100644
--- a/chrome/test/data/webui/settings/android_apps_page_test.js
+++ b/chrome/test/data/webui/settings/android_apps_page_test.js
@@ -20,7 +20,7 @@
   /** @override */
   requestAndroidAppsInfo: function() {
     this.methodCalled('requestAndroidAppsInfo');
-    cr.webUIListenerCallback('android-apps-info-update', {appReady: false});
+    this.setAndroidAppsState(false, false);
   },
 
   /** override */
@@ -28,10 +28,14 @@
     this.methodCalled('showAndroidAppsSettings');
   },
 
-  setAppReady: function(ready) {
+  setAndroidAppsState: function(playStoreEnabled, settingsAppAvailable) {
     // We need to make sure to pass a new object here, otherwise the property
     // change event may not get fired in the listener.
-    cr.webUIListenerCallback('android-apps-info-update', {appReady: ready});
+    var appsInfo = {
+      playStoreEnabled: playStoreEnabled,
+      settingsAppAvailable: settingsAppAvailable,
+    };
+    cr.webUIListenerCallback('android-apps-info-update', appsInfo);
   },
 };
 
@@ -62,7 +66,7 @@
 
       return androidAppsBrowserProxy.whenCalled('requestAndroidAppsInfo')
           .then(function() {
-            androidAppsBrowserProxy.setAppReady(false);
+            androidAppsBrowserProxy.setAndroidAppsState(false, false);
           });
     });
 
@@ -75,7 +79,7 @@
       Polymer.dom.flush();
       assertTrue(androidAppsPage.prefs.arc.enabled.value);
 
-      androidAppsBrowserProxy.setAppReady(true);
+      androidAppsBrowserProxy.setAndroidAppsState(true, false);
       Polymer.dom.flush();
       assertTrue(!!androidAppsPage.$$('.subpage-arrow'));
     });
@@ -84,11 +88,25 @@
   suite('SubPage', function() {
     var subpage;
 
+    /**
+     * Returns a new promise that resolves after a window 'popstate' event.
+     * @return {!Promise}
+     */
+    function whenPopState() {
+      return new Promise(function(resolve) {
+        window.addEventListener('popstate', function callback() {
+          window.removeEventListener('popstate', callback);
+          resolve();
+        });
+      });
+    }
+
     setup(function() {
       androidAppsPage.prefs = {arc: {enabled: {value: true}}};
       return androidAppsBrowserProxy.whenCalled('requestAndroidAppsInfo')
           .then(function() {
-            androidAppsBrowserProxy.setAppReady(true);
+            settings.navigateTo(settings.Route.ANDROID_APPS);
+            androidAppsBrowserProxy.setAndroidAppsState(true, false);
             MockInteractions.tap(androidAppsPage.$$('#android-apps'));
             Polymer.dom.flush();
             subpage = androidAppsPage.$$('settings-android-apps-subpage');
@@ -97,8 +115,19 @@
     });
 
     test('Sanity', function() {
-      assertTrue(!!subpage.$$('#manageApps'));
       assertTrue(!!subpage.$$('#remove'));
+      assertTrue(!!subpage.$$('#manageApps'));
+    });
+
+    test('ManageAppsUpdate', function() {
+      var manageApps = subpage.$$('#manageApps');
+      assertTrue(manageApps.hidden);
+      androidAppsBrowserProxy.setAndroidAppsState(true, true);
+      Polymer.dom.flush();
+      assertFalse(manageApps.hidden);
+      androidAppsBrowserProxy.setAndroidAppsState(true, false);
+      Polymer.dom.flush();
+      assertTrue(manageApps.hidden);
     });
 
     test('Disable', function() {
@@ -108,10 +137,22 @@
 
       var remove = subpage.$$('#remove');
       assertTrue(!!remove);
-      MockInteractions.tap(remove);
 
+      subpage.onRemoveTap_();
       Polymer.dom.flush();
       assertTrue(dialog.open);
+      dialog.close();
+    });
+
+    test('HideOnDisable', function() {
+      assertEquals(settings.getCurrentRoute(),
+                   settings.Route.ANDROID_APPS_DETAILS);
+      androidAppsBrowserProxy.setAndroidAppsState(false, false);
+      Polymer.dom.flush();
+      return whenPopState().then(function() {
+        assertEquals(settings.getCurrentRoute(),
+            settings.Route.ANDROID_APPS);
+      });
     });
   });
 
@@ -129,7 +170,7 @@
       };
       return androidAppsBrowserProxy.whenCalled('requestAndroidAppsInfo')
           .then(function() {
-            androidAppsBrowserProxy.setAppReady(true);
+            androidAppsBrowserProxy.setAndroidAppsState(true, true);
             MockInteractions.tap(androidAppsPage.$$('#android-apps'));
             Polymer.dom.flush();
             subpage = androidAppsPage.$$('settings-android-apps-subpage');
diff --git a/components/autofill/content/common/BUILD.gn b/components/autofill/content/common/BUILD.gn
index 54a5cba..9e84c353 100644
--- a/components/autofill/content/common/BUILD.gn
+++ b/components/autofill/content/common/BUILD.gn
@@ -30,9 +30,6 @@
     "//ui/gfx/geometry/mojo",
     "//url/mojo:url_mojom_gurl",
   ]
-
-  # TODO(crbug.com/714018): Convert the implementation to use OnceCallback.
-  use_once_callback = false
 }
 
 mojom("mojo_types") {
@@ -55,9 +52,6 @@
   public_deps = [
     ":mojo_types",
   ]
-
-  # TODO(crbug.com/714018): Convert the implementation to use OnceCallback.
-  use_once_callback = false
 }
 
 source_set("unit_tests") {
diff --git a/components/autofill/content/common/autofill_types_struct_traits_unittest.cc b/components/autofill/content/common/autofill_types_struct_traits_unittest.cc
index ce4e7b4..2fa52408c 100644
--- a/components/autofill/content/common/autofill_types_struct_traits_unittest.cc
+++ b/components/autofill/content/common/autofill_types_struct_traits_unittest.cc
@@ -2,6 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include <utility>
+
 #include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
 #include "base/strings/utf_string_conversions.h"
@@ -208,49 +210,48 @@
   }
 
   // mojom::TypeTraitsTest:
-  void PassFormData(const FormData& s,
-                    const PassFormDataCallback& callback) override {
-    callback.Run(s);
+  void PassFormData(const FormData& s, PassFormDataCallback callback) override {
+    std::move(callback).Run(s);
   }
 
   void PassFormFieldData(const FormFieldData& s,
-                         const PassFormFieldDataCallback& callback) override {
-    callback.Run(s);
+                         PassFormFieldDataCallback callback) override {
+    std::move(callback).Run(s);
   }
 
   void PassFormDataPredictions(
       const FormDataPredictions& s,
-      const PassFormDataPredictionsCallback& callback) override {
-    callback.Run(s);
+      PassFormDataPredictionsCallback callback) override {
+    std::move(callback).Run(s);
   }
 
   void PassFormFieldDataPredictions(
       const FormFieldDataPredictions& s,
-      const PassFormFieldDataPredictionsCallback& callback) override {
-    callback.Run(s);
+      PassFormFieldDataPredictionsCallback callback) override {
+    std::move(callback).Run(s);
   }
 
   void PassPasswordFormFillData(
       const PasswordFormFillData& s,
-      const PassPasswordFormFillDataCallback& callback) override {
-    callback.Run(s);
+      PassPasswordFormFillDataCallback callback) override {
+    std::move(callback).Run(s);
   }
 
   void PassPasswordFormGenerationData(
       const PasswordFormGenerationData& s,
-      const PassPasswordFormGenerationDataCallback& callback) override {
-    callback.Run(s);
+      PassPasswordFormGenerationDataCallback callback) override {
+    std::move(callback).Run(s);
   }
 
   void PassPasswordForm(const PasswordForm& s,
-                        const PassPasswordFormCallback& callback) override {
-    callback.Run(s);
+                        PassPasswordFormCallback callback) override {
+    std::move(callback).Run(s);
   }
 
   void PassFormsPredictionsMap(
       const FormsPredictionsMap& s,
-      const PassFormsPredictionsMapCallback& callback) override {
-    callback.Run(s);
+      PassFormsPredictionsMapCallback callback) override {
+    std::move(callback).Run(s);
   }
 
  private:
diff --git a/components/autofill/content/renderer/password_autofill_agent.cc b/components/autofill/content/renderer/password_autofill_agent.cc
index e73ef7c..23cdb1a1 100644
--- a/components/autofill/content/renderer/password_autofill_agent.cc
+++ b/components/autofill/content/renderer/password_autofill_agent.cc
@@ -1546,7 +1546,7 @@
 }
 
 void PasswordAutofillAgent::FindFocusedPasswordForm(
-    const FindFocusedPasswordFormCallback& callback) {
+    FindFocusedPasswordFormCallback callback) {
   std::unique_ptr<PasswordForm> password_form;
 
   blink::WebElement element =
@@ -1577,7 +1577,7 @@
 
   password_form->submission_event =
       PasswordForm::SubmissionIndicatorEvent::MANUAL_SAVE;
-  callback.Run(*password_form);
+  std::move(callback).Run(*password_form);
 }
 
 ////////////////////////////////////////////////////////////////////////////////
diff --git a/components/autofill/content/renderer/password_autofill_agent.h b/components/autofill/content/renderer/password_autofill_agent.h
index b8f80e7..86485be9 100644
--- a/components/autofill/content/renderer/password_autofill_agent.h
+++ b/components/autofill/content/renderer/password_autofill_agent.h
@@ -59,7 +59,7 @@
   void AutofillUsernameAndPasswordDataReceived(
       const FormsPredictionsMap& predictions) override;
   void FindFocusedPasswordForm(
-      const FindFocusedPasswordFormCallback& callback) override;
+      FindFocusedPasswordFormCallback callback) override;
 
   // WebFrameClient editor related calls forwarded by AutofillAgent.
   // If they return true, it indicates the event was consumed and should not
diff --git a/components/password_manager/content/browser/content_password_manager_driver_unittest.cc b/components/password_manager/content/browser/content_password_manager_driver_unittest.cc
index 95c0809d..ad35493 100644
--- a/components/password_manager/content/browser/content_password_manager_driver_unittest.cc
+++ b/components/password_manager/content/browser/content_password_manager_driver_unittest.cc
@@ -89,7 +89,7 @@
       const autofill::FormsPredictionsMap& predictions) override {}
 
   void FindFocusedPasswordForm(
-      const FindFocusedPasswordFormCallback& callback) override {}
+      FindFocusedPasswordFormCallback callback) override {}
 
   // Records whether SetLoggingState() gets called.
   bool called_set_logging_state_;
diff --git a/components/payments/content/payment_request_spec.cc b/components/payments/content/payment_request_spec.cc
index 5ba0670..0e8261f 100644
--- a/components/payments/content/payment_request_spec.cc
+++ b/components/payments/content/payment_request_spec.cc
@@ -115,17 +115,16 @@
 }
 
 base::string16 PaymentRequestSpec::GetFormattedCurrencyAmount(
-    const std::string& amount) {
+    const mojom::PaymentCurrencyAmountPtr& currency_amount) {
   CurrencyFormatter* formatter = GetOrCreateCurrencyFormatter(
-      details_->total->amount->currency,
-      details_->total->amount->currency_system, app_locale_);
-  return formatter->Format(amount);
+      currency_amount->currency, currency_amount->currency_system, app_locale_);
+  return formatter->Format(currency_amount->value);
 }
 
-std::string PaymentRequestSpec::GetFormattedCurrencyCode() {
+std::string PaymentRequestSpec::GetFormattedCurrencyCode(
+    const mojom::PaymentCurrencyAmountPtr& currency_amount) {
   CurrencyFormatter* formatter = GetOrCreateCurrencyFormatter(
-      details_->total->amount->currency,
-      details_->total->amount->currency_system, app_locale_);
+      currency_amount->currency, currency_amount->currency_system, app_locale_);
 
   return formatter->formatted_currency_code();
 }
@@ -137,6 +136,15 @@
   }
 }
 
+bool PaymentRequestSpec::IsMixedCurrency() const {
+  const std::string& total_currency = details_->total->amount->currency;
+  return std::any_of(details_->display_items.begin(),
+                     details_->display_items.end(),
+                     [&total_currency](const mojom::PaymentItemPtr& item) {
+                       return item->amount->currency != total_currency;
+                     });
+}
+
 void PaymentRequestSpec::PopulateValidatedMethodData(
     const std::vector<mojom::PaymentMethodDataPtr>& method_data_mojom) {
   std::vector<PaymentMethodData> method_data_vector;
@@ -216,11 +224,14 @@
     const std::string& currency_code,
     const std::string& currency_system,
     const std::string& locale_name) {
-  if (!currency_formatter_) {
-    currency_formatter_.reset(
-        new CurrencyFormatter(currency_code, currency_system, locale_name));
-  }
-  return currency_formatter_.get();
+  // Create a currency formatter for |currency_code|, or if already created
+  // return the cached version.
+  std::pair<std::map<std::string, CurrencyFormatter>::iterator, bool>
+      emplace_result = currency_formatters_.emplace(
+          std::piecewise_construct, std::forward_as_tuple(currency_code),
+          std::forward_as_tuple(currency_code, currency_system, locale_name));
+
+  return &(emplace_result.first->second);
 }
 
 }  // namespace payments
diff --git a/components/payments/content/payment_request_spec.h b/components/payments/content/payment_request_spec.h
index e7bc5ff..a5df017b 100644
--- a/components/payments/content/payment_request_spec.h
+++ b/components/payments/content/payment_request_spec.h
@@ -87,15 +87,15 @@
   // not supported at all, or specified directly in supportedMethods.
   bool IsMethodSupportedThroughBasicCard(const std::string& method_name);
 
-  // Uses CurrencyFormatter to format |amount| with the currency symbol for this
-  // request's currency. Will use currency of the "total" display item, because
-  // all items are supposed to have the same currency in a given request.
-  base::string16 GetFormattedCurrencyAmount(const std::string& amount);
+  // Uses CurrencyFormatter to format the value of |currency_amount| with the
+  // currency symbol for its currency.
+  base::string16 GetFormattedCurrencyAmount(
+      const mojom::PaymentCurrencyAmountPtr& currency_amount);
 
-  // Uses CurrencyFormatter to get the formatted currency code for this
-  // request's currency. Will use currency of the "total" display item, because
-  // all items are supposed to have the same currency in a given request.
-  std::string GetFormattedCurrencyCode();
+  // Uses CurrencyFormatter to get the formatted currency code for
+  // |currency_amount|'s currency.
+  std::string GetFormattedCurrencyCode(
+      const mojom::PaymentCurrencyAmountPtr& currency_amount);
 
   mojom::PaymentShippingOption* selected_shipping_option() const {
     return selected_shipping_option_;
@@ -110,6 +110,8 @@
 
   void StartWaitingForUpdateWith(UpdateReason reason);
 
+  bool IsMixedCurrency() const;
+
  private:
   friend class PaymentRequestDialogView;
   void add_observer_for_testing(Observer* observer_for_testing) {
@@ -148,7 +150,8 @@
   mojom::PaymentShippingOption* selected_shipping_option_;
   base::string16 selected_shipping_option_error_;
 
-  std::unique_ptr<CurrencyFormatter> currency_formatter_;
+  // One currency formatter is instantiated and cached per currency code.
+  std::map<std::string, CurrencyFormatter> currency_formatters_;
 
   // A list/set of supported basic card networks. The list is used to keep the
   // order in which they were specified by the merchant. The set is used for
diff --git a/components/payments/content/payment_request_spec_unittest.cc b/components/payments/content/payment_request_spec_unittest.cc
index 28d2774b..235a17ad 100644
--- a/components/payments/content/payment_request_spec_unittest.cc
+++ b/components/payments/content/payment_request_spec_unittest.cc
@@ -341,4 +341,93 @@
             spec()->selected_shipping_option_error());
 }
 
+TEST_F(PaymentRequestSpecTest, SingleCurrencyWithoutDisplayItems) {
+  mojom::PaymentDetailsPtr details = mojom::PaymentDetails::New();
+  mojom::PaymentItemPtr total = mojom::PaymentItem::New();
+  mojom::PaymentCurrencyAmountPtr amount = mojom::PaymentCurrencyAmount::New();
+  amount->currency = "USD";
+  total->amount = std::move(amount);
+  details->total = std::move(total);
+
+  RecreateSpecWithOptionsAndDetails(mojom::PaymentOptions::New(),
+                                    std::move(details));
+  // If the request only has a total, it must not have mixed currencies.
+  EXPECT_FALSE(spec()->IsMixedCurrency());
+}
+
+TEST_F(PaymentRequestSpecTest, SingleCurrencyWithDisplayItems) {
+  mojom::PaymentDetailsPtr details = mojom::PaymentDetails::New();
+  mojom::PaymentItemPtr total = mojom::PaymentItem::New();
+  mojom::PaymentCurrencyAmountPtr amount = mojom::PaymentCurrencyAmount::New();
+  amount->currency = "USD";
+  total->amount = std::move(amount);
+  details->total = std::move(total);
+
+  mojom::PaymentItemPtr display_item = mojom::PaymentItem::New();
+  mojom::PaymentCurrencyAmountPtr display_amount =
+      mojom::PaymentCurrencyAmount::New();
+  display_amount->currency = "USD";
+  display_item->amount = std::move(display_amount);
+  details->display_items.push_back(std::move(display_item));
+
+  RecreateSpecWithOptionsAndDetails(mojom::PaymentOptions::New(),
+                                    std::move(details));
+  // Both the total and the display item have matching currency codes, this
+  // isn't a mixed currency case.
+  EXPECT_FALSE(spec()->IsMixedCurrency());
+}
+
+TEST_F(PaymentRequestSpecTest, MultipleCurrenciesWithOneDisplayItem) {
+  mojom::PaymentDetailsPtr details = mojom::PaymentDetails::New();
+  mojom::PaymentItemPtr total = mojom::PaymentItem::New();
+  mojom::PaymentCurrencyAmountPtr amount = mojom::PaymentCurrencyAmount::New();
+  amount->currency = "USD";
+  total->amount = std::move(amount);
+  details->total = std::move(total);
+
+  mojom::PaymentItemPtr display_item = mojom::PaymentItem::New();
+  mojom::PaymentCurrencyAmountPtr display_amount =
+      mojom::PaymentCurrencyAmount::New();
+  display_amount->currency = "CAD";
+  display_item->amount = std::move(display_amount);
+  details->display_items.push_back(std::move(display_item));
+
+  RecreateSpecWithOptionsAndDetails(mojom::PaymentOptions::New(),
+                                    std::move(details));
+
+  // The display item currency and the total's currency don't match, this is a
+  // mixed currencies case.
+  EXPECT_TRUE(spec()->IsMixedCurrency());
+}
+
+TEST_F(PaymentRequestSpecTest, MultipleCurrenciesWithTwoDisplayItem) {
+  mojom::PaymentDetailsPtr details = mojom::PaymentDetails::New();
+  mojom::PaymentItemPtr total = mojom::PaymentItem::New();
+  mojom::PaymentCurrencyAmountPtr amount = mojom::PaymentCurrencyAmount::New();
+  amount->currency = "USD";
+  total->amount = std::move(amount);
+  details->total = std::move(total);
+
+  mojom::PaymentItemPtr display_item1 = mojom::PaymentItem::New();
+  mojom::PaymentCurrencyAmountPtr display_amount1 =
+      mojom::PaymentCurrencyAmount::New();
+  display_amount1->currency = "CAD";
+  display_item1->amount = std::move(display_amount1);
+  details->display_items.push_back(std::move(display_item1));
+
+  mojom::PaymentItemPtr display_item2 = mojom::PaymentItem::New();
+  mojom::PaymentCurrencyAmountPtr display_amount2 =
+      mojom::PaymentCurrencyAmount::New();
+  display_amount2->currency = "USD";
+  display_item2->amount = std::move(display_amount2);
+  details->display_items.push_back(std::move(display_item2));
+
+  RecreateSpecWithOptionsAndDetails(mojom::PaymentOptions::New(),
+                                    std::move(details));
+
+  // At least one of the display items has a different currency, this is a mixed
+  // currency case.
+  EXPECT_TRUE(spec()->IsMixedCurrency());
+}
+
 }  // namespace payments
diff --git a/components/payments_strings.grdp b/components/payments_strings.grdp
index 7c6d20cc..37cf226c 100644
--- a/components/payments_strings.grdp
+++ b/components/payments_strings.grdp
@@ -115,6 +115,9 @@
   <message name="IDS_PAYMENTS_CARD_AND_ADDRESS_SETTINGS_SIGNED_OUT" desc="Label of the section containing the origin description and the link to go to the settings page for card and address options. This label is used when the user is not signed in." formatter_data="android_java">
     Cards and addresses are from Chrome. You can manage them in <ph name="BEGIN_LINK">BEGIN_LINK</ph>Settings<ph name="END_LINK">END_LINK</ph>.
   </message>
+  <message name="IDS_PAYMENTS_CANCEL_PAYMENT" desc="Label of the secondary button in payment request editors. Clicking that button closes the dialog and aborts the payment request completely">
+    Cancel Payment
+  </message>
 
   <!-- Credit Card form -->
   <if expr="is_ios">
diff --git a/components/translate/core/browser/translate_infobar_delegate.cc b/components/translate/core/browser/translate_infobar_delegate.cc
index 5fa42a5c..f600852 100644
--- a/components/translate/core/browser/translate_infobar_delegate.cc
+++ b/components/translate/core/browser/translate_infobar_delegate.cc
@@ -46,6 +46,10 @@
 const int kNeverTranslateMinCount = 3;
 #endif
 
+// For Compact UI, if number of consecutive translations is equal to this
+// number, infobar will automatically trigger "Always Translate".
+const int kAcceptCountThreshold = 5;
+
 }  // namespace
 
 const base::Feature kTranslateCompactUI{"TranslateCompactUI",
@@ -298,6 +302,12 @@
 }
 #endif
 
+bool TranslateInfoBarDelegate::ShouldAutoAlwaysTranslate() {
+  return (IsCompactUIEnabled() &&
+          prefs_->GetTranslationAcceptedCount(original_language_code()) ==
+              kAcceptCountThreshold);
+}
+
 // static
 void TranslateInfoBarDelegate::GetAfterTranslateStrings(
     std::vector<base::string16>* strings,
@@ -378,7 +388,8 @@
 void TranslateInfoBarDelegate::InfoBarDismissed() {
   if (step_ != translate::TRANSLATE_STEP_BEFORE_TRANSLATE)
     return;
-
+  if (IsCompactUIEnabled())
+    return;
   // The user closed the infobar without clicking the translate button.
   TranslationDeclined();
   UMA_HISTOGRAM_BOOLEAN("Translate.DeclineTranslateCloseInfobar", true);
diff --git a/components/translate/core/browser/translate_infobar_delegate.h b/components/translate/core/browser/translate_infobar_delegate.h
index 1e48a64..c0cdc374 100644
--- a/components/translate/core/browser/translate_infobar_delegate.h
+++ b/components/translate/core/browser/translate_infobar_delegate.h
@@ -167,6 +167,10 @@
   bool ShouldShowNeverTranslateShortcut();
   bool ShouldShowAlwaysTranslateShortcut();
 
+  // Called by translate compact infobar.  This check whether we should
+  // automatically trigger "Always Translate".
+  bool ShouldAutoAlwaysTranslate();
+
 #if defined(OS_IOS)
   // Shows the Infobar offering to never translate the language or the site.
   void ShowNeverTranslateInfobar();
diff --git a/content/browser/browser_thread_impl.cc b/content/browser/browser_thread_impl.cc
index fa8e4911..205340ed 100644
--- a/content/browser/browser_thread_impl.cc
+++ b/content/browser/browser_thread_impl.cc
@@ -133,7 +133,7 @@
   // This array is filled either as the underlying threads start and invoke
   // Init() or in RedirectThreadIDToTaskRunner() for threads that are being
   // redirected. It is not emptied during shutdown in order to support
-  // RunsTasksOnCurrentThread() until the very end.
+  // RunsTasksInCurrentSequence() until the very end.
   scoped_refptr<base::SingleThreadTaskRunner>
       task_runners[BrowserThread::ID_COUNT];
 
@@ -208,7 +208,7 @@
     // instead of BrowserThreadImpl::Start.*().
     DCHECK_EQ(globals.states[identifier_], BrowserThreadState::RUNNING);
     DCHECK(globals.task_runners[identifier_]);
-    DCHECK(globals.task_runners[identifier_]->RunsTasksOnCurrentThread());
+    DCHECK(globals.task_runners[identifier_]->RunsTasksInCurrentSequence());
   }
 #endif  // DCHECK_IS_ON()
 
@@ -574,7 +574,7 @@
   DCHECK_GE(identifier, 0);
   DCHECK_LT(identifier, ID_COUNT);
   return globals.task_runners[identifier] &&
-         globals.task_runners[identifier]->RunsTasksOnCurrentThread();
+         globals.task_runners[identifier]->RunsTasksInCurrentSequence();
 }
 
 // static
@@ -661,7 +661,7 @@
   base::AutoLock lock(globals.lock);
   for (int i = 0; i < ID_COUNT; ++i) {
     if (globals.task_runners[i] &&
-        globals.task_runners[i]->RunsTasksOnCurrentThread()) {
+        globals.task_runners[i]->RunsTasksInCurrentSequence()) {
       *identifier = static_cast<ID>(i);
       return true;
     }
diff --git a/content/browser/byte_stream.cc b/content/browser/byte_stream.cc
index 0bb824a..0209bb85 100644
--- a/content/browser/byte_stream.cc
+++ b/content/browser/byte_stream.cc
@@ -191,7 +191,7 @@
 }
 
 ByteStreamWriterImpl::~ByteStreamWriterImpl() {
-  // No RunsTasksOnCurrentThread() check to allow deleting a created writer
+  // No RunsTasksInCurrentSequence() check to allow deleting a created writer
   // before we start using it. Once started, should be deleted on the specified
   // task runner.
   my_lifetime_flag_->is_alive = false;
@@ -208,7 +208,7 @@
 
 bool ByteStreamWriterImpl::Write(
     scoped_refptr<net::IOBuffer> buffer, size_t byte_count) {
-  DCHECK(my_task_runner_->RunsTasksOnCurrentThread());
+  DCHECK(my_task_runner_->RunsTasksInCurrentSequence());
 
   // Check overflow.
   //
@@ -233,24 +233,24 @@
 }
 
 void ByteStreamWriterImpl::Flush() {
-  DCHECK(my_task_runner_->RunsTasksOnCurrentThread());
+  DCHECK(my_task_runner_->RunsTasksInCurrentSequence());
   if (input_contents_size_ > 0)
     PostToPeer(false, 0);
 }
 
 void ByteStreamWriterImpl::Close(int status) {
-  DCHECK(my_task_runner_->RunsTasksOnCurrentThread());
+  DCHECK(my_task_runner_->RunsTasksInCurrentSequence());
   PostToPeer(true, status);
 }
 
 void ByteStreamWriterImpl::RegisterCallback(
     const base::Closure& source_callback) {
-  DCHECK(my_task_runner_->RunsTasksOnCurrentThread());
+  DCHECK(my_task_runner_->RunsTasksInCurrentSequence());
   space_available_callback_ = source_callback;
 }
 
 size_t ByteStreamWriterImpl::GetTotalBufferedBytes() const {
-  DCHECK(my_task_runner_->RunsTasksOnCurrentThread());
+  DCHECK(my_task_runner_->RunsTasksInCurrentSequence());
   // This sum doesn't overflow since Write() fails if this sum is going to
   // overflow.
   return input_contents_size_ + output_size_used_;
@@ -267,7 +267,7 @@
 }
 
 void ByteStreamWriterImpl::UpdateWindowInternal(size_t bytes_consumed) {
-  DCHECK(my_task_runner_->RunsTasksOnCurrentThread());
+  DCHECK(my_task_runner_->RunsTasksInCurrentSequence());
 
   bool was_above_limit = GetTotalBufferedBytes() > total_buffer_size_;
 
@@ -283,7 +283,7 @@
 }
 
 void ByteStreamWriterImpl::PostToPeer(bool complete, int status) {
-  DCHECK(my_task_runner_->RunsTasksOnCurrentThread());
+  DCHECK(my_task_runner_->RunsTasksInCurrentSequence());
   // Valid contexts in which to call.
   DCHECK(complete || 0 != input_contents_size_);
 
@@ -323,7 +323,7 @@
 }
 
 ByteStreamReaderImpl::~ByteStreamReaderImpl() {
-  // No RunsTasksOnCurrentThread() check to allow deleting a created writer
+  // No RunsTasksInCurrentSequence() check to allow deleting a created writer
   // before we start using it. Once started, should be deleted on the specified
   // task runner.
   my_lifetime_flag_->is_alive = false;
@@ -341,7 +341,7 @@
 ByteStreamReaderImpl::StreamState
 ByteStreamReaderImpl::Read(scoped_refptr<net::IOBuffer>* data,
                            size_t* length) {
-  DCHECK(my_task_runner_->RunsTasksOnCurrentThread());
+  DCHECK(my_task_runner_->RunsTasksInCurrentSequence());
 
   if (available_contents_.size()) {
     *data = available_contents_.front().first;
@@ -359,14 +359,14 @@
 }
 
 int ByteStreamReaderImpl::GetStatus() const {
-  DCHECK(my_task_runner_->RunsTasksOnCurrentThread());
+  DCHECK(my_task_runner_->RunsTasksInCurrentSequence());
   DCHECK(received_status_);
   return status_;
 }
 
 void ByteStreamReaderImpl::RegisterCallback(
     const base::Closure& sink_callback) {
-  DCHECK(my_task_runner_->RunsTasksOnCurrentThread());
+  DCHECK(my_task_runner_->RunsTasksInCurrentSequence());
 
   data_available_callback_ = sink_callback;
 }
@@ -391,7 +391,7 @@
     size_t buffer_size,
     bool source_complete,
     int status) {
-  DCHECK(my_task_runner_->RunsTasksOnCurrentThread());
+  DCHECK(my_task_runner_->RunsTasksInCurrentSequence());
 
   bool was_empty = available_contents_.empty();
 
@@ -418,7 +418,7 @@
 // Currently we do that whenever we've got unreported consumption
 // greater than 1/3 of total size.
 void ByteStreamReaderImpl::MaybeUpdateInput() {
-  DCHECK(my_task_runner_->RunsTasksOnCurrentThread());
+  DCHECK(my_task_runner_->RunsTasksInCurrentSequence());
 
   if (unreported_consumed_bytes_ <=
       total_buffer_size_ / kFractionReadBeforeWindowUpdate)
diff --git a/content/browser/compositor/gpu_process_transport_factory.cc b/content/browser/compositor/gpu_process_transport_factory.cc
index fbad9cf..47b95f6 100644
--- a/content/browser/compositor/gpu_process_transport_factory.cc
+++ b/content/browser/compositor/gpu_process_transport_factory.cc
@@ -42,6 +42,7 @@
 #include "content/browser/gpu/browser_gpu_memory_buffer_manager.h"
 #include "content/browser/gpu/gpu_data_manager_impl.h"
 #include "content/browser/renderer_host/render_widget_host_impl.h"
+#include "content/common/gpu_stream_constants.h"
 #include "content/public/common/content_switches.h"
 #include "gpu/GLES2/gl2extchromium.h"
 #include "gpu/command_buffer/client/gles2_interface.h"
@@ -133,6 +134,11 @@
       content::GpuDataManagerImpl::GetInstance()->CanUseGpuBrowserCompositor());
   DCHECK(gpu_channel_host);
 
+  // All browser contexts get the same stream id because we don't use sync
+  // tokens for browser surfaces.
+  int32_t stream_id = content::kGpuStreamIdDefault;
+  gpu::SchedulingPriority stream_priority = content::kGpuStreamPriorityUI;
+
   // This is called from a few places to create different contexts:
   // - The shared main thread context (offscreen).
   // - The compositor context, which is used by the browser compositor
@@ -161,10 +167,9 @@
 
   GURL url("chrome://gpu/GpuProcessTransportFactory::CreateContextCommon");
   return make_scoped_refptr(new ui::ContextProviderCommandBuffer(
-      std::move(gpu_channel_host), gpu::GPU_STREAM_DEFAULT,
-      gpu::GpuStreamPriority::NORMAL, surface_handle, url, automatic_flushes,
-      support_locking, gpu::SharedMemoryLimits(), attributes,
-      shared_context_provider, type));
+      std::move(gpu_channel_host), stream_id, stream_priority, surface_handle,
+      url, automatic_flushes, support_locking, gpu::SharedMemoryLimits(),
+      attributes, shared_context_provider, type));
 }
 
 #if defined(OS_MACOSX)
diff --git a/content/browser/dom_storage/dom_storage_task_runner.cc b/content/browser/dom_storage/dom_storage_task_runner.cc
index edfdc722..f5af6384 100644
--- a/content/browser/dom_storage/dom_storage_task_runner.cc
+++ b/content/browser/dom_storage/dom_storage_task_runner.cc
@@ -25,8 +25,8 @@
 DOMStorageWorkerPoolTaskRunner::~DOMStorageWorkerPoolTaskRunner() = default;
 
 bool DOMStorageWorkerPoolTaskRunner::RunsTasksInCurrentSequence() const {
-  return primary_sequence_->RunsTasksOnCurrentThread() ||
-         commit_sequence_->RunsTasksOnCurrentThread();
+  return primary_sequence_->RunsTasksInCurrentSequence() ||
+         commit_sequence_->RunsTasksInCurrentSequence();
 }
 
 bool DOMStorageWorkerPoolTaskRunner::PostDelayedTask(
@@ -45,11 +45,11 @@
 }
 
 void DOMStorageWorkerPoolTaskRunner::AssertIsRunningOnPrimarySequence() const {
-  DCHECK(primary_sequence_->RunsTasksOnCurrentThread());
+  DCHECK(primary_sequence_->RunsTasksInCurrentSequence());
 }
 
 void DOMStorageWorkerPoolTaskRunner::AssertIsRunningOnCommitSequence() const {
-  DCHECK(commit_sequence_->RunsTasksOnCurrentThread());
+  DCHECK(commit_sequence_->RunsTasksInCurrentSequence());
 }
 
 scoped_refptr<base::SequencedTaskRunner>
@@ -87,11 +87,11 @@
 }
 
 void MockDOMStorageTaskRunner::AssertIsRunningOnPrimarySequence() const {
-  DCHECK(RunsTasksOnCurrentThread());
+  DCHECK(RunsTasksInCurrentSequence());
 }
 
 void MockDOMStorageTaskRunner::AssertIsRunningOnCommitSequence() const {
-  DCHECK(RunsTasksOnCurrentThread());
+  DCHECK(RunsTasksInCurrentSequence());
 }
 
 scoped_refptr<base::SequencedTaskRunner>
diff --git a/content/browser/fileapi/browser_file_system_helper.cc b/content/browser/fileapi/browser_file_system_helper.cc
index c74b516..f8da5a6a 100644
--- a/content/browser/fileapi/browser_file_system_helper.cc
+++ b/content/browser/fileapi/browser_file_system_helper.cc
@@ -116,7 +116,7 @@
                          const GURL& path,
                          base::FilePath* platform_path) {
   DCHECK(context->default_file_task_runner()->
-         RunsTasksOnCurrentThread());
+         RunsTasksInCurrentSequence());
   DCHECK(platform_path);
   *platform_path = base::FilePath();
   storage::FileSystemURL url(context->CrackURL(path));
diff --git a/content/browser/gpu/compositor_util.cc b/content/browser/gpu/compositor_util.cc
index a40bc8f1..bcd0f5b 100644
--- a/content/browser/gpu/compositor_util.cc
+++ b/content/browser/gpu/compositor_util.cc
@@ -239,10 +239,11 @@
 
   if (command_line.HasSwitch(switches::kDisableGpuAsyncWorkerContext))
     return false;
-  else if (command_line.HasSwitch(switches::kEnableGpuAsyncWorkerContext))
-    return true;
 
-  return false;
+  if (command_line.HasSwitch(switches::kDisableGpuScheduler))
+    return false;
+
+  return command_line.HasSwitch(switches::kEnableGpuScheduler);
 }
 
 bool IsForceGpuRasterizationEnabled() {
diff --git a/content/browser/gpu/gpu_ipc_browsertests.cc b/content/browser/gpu/gpu_ipc_browsertests.cc
index 492ad85b..de30097 100644
--- a/content/browser/gpu/gpu_ipc_browsertests.cc
+++ b/content/browser/gpu/gpu_ipc_browsertests.cc
@@ -9,6 +9,7 @@
 #include "content/browser/compositor/image_transport_factory.h"
 #include "content/browser/gpu/browser_gpu_channel_host_factory.h"
 #include "content/browser/gpu/gpu_process_host.h"
+#include "content/common/gpu_stream_constants.h"
 #include "content/public/browser/gpu_data_manager.h"
 #include "content/public/browser/gpu_utils.h"
 #include "content/public/common/content_switches.h"
@@ -37,8 +38,8 @@
   constexpr bool automatic_flushes = false;
   constexpr bool support_locking = false;
   return make_scoped_refptr(new ui::ContextProviderCommandBuffer(
-      std::move(gpu_channel_host), gpu::GPU_STREAM_DEFAULT,
-      gpu::GpuStreamPriority::NORMAL, gpu::kNullSurfaceHandle, GURL(),
+      std::move(gpu_channel_host), content::kGpuStreamIdDefault,
+      content::kGpuStreamPriorityDefault, gpu::kNullSurfaceHandle, GURL(),
       automatic_flushes, support_locking, gpu::SharedMemoryLimits(), attributes,
       nullptr, ui::command_buffer_metrics::OFFSCREEN_CONTEXT_FOR_TESTING));
 }
diff --git a/content/browser/indexed_db/indexed_db_active_blob_registry.cc b/content/browser/indexed_db/indexed_db_active_blob_registry.cc
index ea2bde2a..a5ea89d 100644
--- a/content/browser/indexed_db/indexed_db_active_blob_registry.cc
+++ b/content/browser/indexed_db/indexed_db_active_blob_registry.cc
@@ -23,7 +23,7 @@
 void IndexedDBActiveBlobRegistry::AddBlobRef(int64_t database_id,
                                              int64_t blob_key) {
   DCHECK(backing_store_);
-  DCHECK(backing_store_->task_runner()->RunsTasksOnCurrentThread());
+  DCHECK(backing_store_->task_runner()->RunsTasksInCurrentSequence());
   DCHECK(KeyPrefix::IsValidDatabaseId(database_id));
   DCHECK(DatabaseMetaDataKey::IsValidBlobKey(blob_key));
   DCHECK(!base::ContainsKey(deleted_dbs_, database_id));
@@ -45,7 +45,7 @@
 void IndexedDBActiveBlobRegistry::ReleaseBlobRef(int64_t database_id,
                                                  int64_t blob_key) {
   DCHECK(backing_store_);
-  DCHECK(backing_store_->task_runner()->RunsTasksOnCurrentThread());
+  DCHECK(backing_store_->task_runner()->RunsTasksInCurrentSequence());
   DCHECK(KeyPrefix::IsValidDatabaseId(database_id));
   DCHECK(DatabaseMetaDataKey::IsValidBlobKey(blob_key));
   const auto& db_pair = use_tracker_.find(database_id);
@@ -85,7 +85,7 @@
 bool IndexedDBActiveBlobRegistry::MarkDeletedCheckIfUsed(int64_t database_id,
                                                          int64_t blob_key) {
   DCHECK(backing_store_);
-  DCHECK(backing_store_->task_runner()->RunsTasksOnCurrentThread());
+  DCHECK(backing_store_->task_runner()->RunsTasksInCurrentSequence());
   DCHECK(KeyPrefix::IsValidDatabaseId(database_id));
   const auto& db_pair = use_tracker_.find(database_id);
   if (db_pair == use_tracker_.end())
diff --git a/content/browser/indexed_db/indexed_db_backing_store.cc b/content/browser/indexed_db/indexed_db_backing_store.cc
index fe068ab0..7711662 100644
--- a/content/browser/indexed_db/indexed_db_backing_store.cc
+++ b/content/browser/indexed_db/indexed_db_backing_store.cc
@@ -2612,7 +2612,7 @@
   // If necessary, update the timestamps on the file as a final
   // step before reporting success.
   void UpdateTimeStamp() {
-    DCHECK(task_runner_->RunsTasksOnCurrentThread());
+    DCHECK(task_runner_->RunsTasksInCurrentSequence());
     if (!base::TouchFile(file_path_, last_modified_, last_modified_)) {
       // TODO(ericu): Complain quietly; timestamp's probably not vital.
     }
@@ -2621,7 +2621,7 @@
 
   // Create an empty file.
   void CreateEmptyFile() {
-    DCHECK(task_runner_->RunsTasksOnCurrentThread());
+    DCHECK(task_runner_->RunsTasksInCurrentSequence());
     base::File file(file_path_,
                     base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE);
     bool success = file.created();
@@ -4153,7 +4153,7 @@
     scoped_refptr<BlobWriteCallback> callback) {
   IDB_TRACE("IndexedDBBackingStore::Transaction::CommitPhaseOne");
   DCHECK(transaction_.get());
-  DCHECK(backing_store_->task_runner()->RunsTasksOnCurrentThread());
+  DCHECK(backing_store_->task_runner()->RunsTasksInCurrentSequence());
 
   Status s;
 
diff --git a/content/browser/indexed_db/indexed_db_browsertest.cc b/content/browser/indexed_db/indexed_db_browsertest.cc
index 934f3c21..0543ece 100644
--- a/content/browser/indexed_db/indexed_db_browsertest.cc
+++ b/content/browser/indexed_db/indexed_db_browsertest.cc
@@ -314,7 +314,7 @@
 static void CopyLevelDBToProfile(Shell* shell,
                                  scoped_refptr<IndexedDBContextImpl> context,
                                  const std::string& test_directory) {
-  DCHECK(context->TaskRunner()->RunsTasksOnCurrentThread());
+  DCHECK(context->TaskRunner()->RunsTasksInCurrentSequence());
   base::FilePath leveldb_dir(FILE_PATH_LITERAL("file__0.indexeddb.leveldb"));
   base::FilePath test_data_dir =
       GetTestFilePath("indexeddb", test_directory.c_str()).Append(leveldb_dir);
diff --git a/content/browser/indexed_db/indexed_db_context_impl.cc b/content/browser/indexed_db/indexed_db_context_impl.cc
index 059d5c67..c79635f 100644
--- a/content/browser/indexed_db/indexed_db_context_impl.cc
+++ b/content/browser/indexed_db/indexed_db_context_impl.cc
@@ -122,7 +122,7 @@
 }
 
 IndexedDBFactory* IndexedDBContextImpl::GetIDBFactory() {
-  DCHECK(TaskRunner()->RunsTasksOnCurrentThread());
+  DCHECK(TaskRunner()->RunsTasksInCurrentSequence());
   if (!factory_.get()) {
     // Prime our cache of origins with existing databases so we can
     // detect when dbs are newly created.
@@ -133,19 +133,19 @@
 }
 
 std::vector<Origin> IndexedDBContextImpl::GetAllOrigins() {
-  DCHECK(TaskRunner()->RunsTasksOnCurrentThread());
+  DCHECK(TaskRunner()->RunsTasksInCurrentSequence());
   std::set<Origin>* origins_set = GetOriginSet();
   return std::vector<Origin>(origins_set->begin(), origins_set->end());
 }
 
 bool IndexedDBContextImpl::HasOrigin(const Origin& origin) {
-  DCHECK(TaskRunner()->RunsTasksOnCurrentThread());
+  DCHECK(TaskRunner()->RunsTasksInCurrentSequence());
   std::set<Origin>* set = GetOriginSet();
   return set->find(origin) != set->end();
 }
 
 std::vector<IndexedDBInfo> IndexedDBContextImpl::GetAllOriginsInfo() {
-  DCHECK(TaskRunner()->RunsTasksOnCurrentThread());
+  DCHECK(TaskRunner()->RunsTasksInCurrentSequence());
   std::vector<Origin> origins = GetAllOrigins();
   std::vector<IndexedDBInfo> result;
   for (const auto& origin : origins) {
@@ -162,7 +162,7 @@
 }
 
 base::ListValue* IndexedDBContextImpl::GetAllOriginsDetails() {
-  DCHECK(TaskRunner()->RunsTasksOnCurrentThread());
+  DCHECK(TaskRunner()->RunsTasksInCurrentSequence());
   std::vector<Origin> origins = GetAllOrigins();
 
   std::sort(origins.begin(), origins.end(), HostNameComparator);
@@ -276,7 +276,7 @@
 }
 
 int IndexedDBContextImpl::GetOriginBlobFileCount(const Origin& origin) {
-  DCHECK(TaskRunner()->RunsTasksOnCurrentThread());
+  DCHECK(TaskRunner()->RunsTasksInCurrentSequence());
   int count = 0;
   base::FileEnumerator file_enumerator(GetBlobStorePath(origin), true,
                                        base::FileEnumerator::FILES);
@@ -293,7 +293,7 @@
 }
 
 int64_t IndexedDBContextImpl::GetOriginDiskUsage(const Origin& origin) {
-  DCHECK(TaskRunner()->RunsTasksOnCurrentThread());
+  DCHECK(TaskRunner()->RunsTasksInCurrentSequence());
   if (data_path_.empty() || !HasOrigin(origin))
     return 0;
   EnsureDiskUsageCacheInitialized(origin);
@@ -301,7 +301,7 @@
 }
 
 base::Time IndexedDBContextImpl::GetOriginLastModified(const Origin& origin) {
-  DCHECK(TaskRunner()->RunsTasksOnCurrentThread());
+  DCHECK(TaskRunner()->RunsTasksInCurrentSequence());
   if (data_path_.empty() || !HasOrigin(origin))
     return base::Time();
   base::FilePath idb_directory = GetLevelDBPath(origin);
@@ -317,7 +317,7 @@
 }
 
 void IndexedDBContextImpl::DeleteForOrigin(const Origin& origin) {
-  DCHECK(TaskRunner()->RunsTasksOnCurrentThread());
+  DCHECK(TaskRunner()->RunsTasksInCurrentSequence());
   ForceClose(origin, FORCE_CLOSE_DELETE_ORIGIN);
   if (data_path_.empty() || !HasOrigin(origin))
     return;
@@ -351,7 +351,7 @@
 
 void IndexedDBContextImpl::CopyOriginData(const Origin& origin,
                                           IndexedDBContext* dest_context) {
-  DCHECK(TaskRunner()->RunsTasksOnCurrentThread());
+  DCHECK(TaskRunner()->RunsTasksInCurrentSequence());
   if (data_path_.empty() || !HasOrigin(origin))
     return;
 
@@ -382,7 +382,7 @@
 
 void IndexedDBContextImpl::ForceClose(const Origin origin,
                                       ForceCloseReason reason) {
-  DCHECK(TaskRunner()->RunsTasksOnCurrentThread());
+  DCHECK(TaskRunner()->RunsTasksInCurrentSequence());
   UMA_HISTOGRAM_ENUMERATION("WebCore.IndexedDB.Context.ForceCloseReason",
                             reason,
                             FORCE_CLOSE_REASON_MAX);
@@ -396,7 +396,7 @@
 }
 
 size_t IndexedDBContextImpl::GetConnectionCount(const Origin& origin) {
-  DCHECK(TaskRunner()->RunsTasksOnCurrentThread());
+  DCHECK(TaskRunner()->RunsTasksInCurrentSequence());
   if (data_path_.empty() || !HasOrigin(origin))
     return 0;
 
@@ -433,7 +433,7 @@
 
 void IndexedDBContextImpl::ConnectionOpened(const Origin& origin,
                                             IndexedDBConnection* connection) {
-  DCHECK(TaskRunner()->RunsTasksOnCurrentThread());
+  DCHECK(TaskRunner()->RunsTasksInCurrentSequence());
   quota_manager_proxy()->NotifyStorageAccessed(
       storage::QuotaClient::kIndexedDatabase, origin.GetURL(),
       storage::kStorageTypeTemporary);
@@ -447,7 +447,7 @@
 
 void IndexedDBContextImpl::ConnectionClosed(const Origin& origin,
                                             IndexedDBConnection* connection) {
-  DCHECK(TaskRunner()->RunsTasksOnCurrentThread());
+  DCHECK(TaskRunner()->RunsTasksInCurrentSequence());
   quota_manager_proxy()->NotifyStorageAccessed(
       storage::QuotaClient::kIndexedDatabase, origin.GetURL(),
       storage::kStorageTypeTemporary);
diff --git a/content/browser/indexed_db/indexed_db_dispatcher_host.cc b/content/browser/indexed_db/indexed_db_dispatcher_host.cc
index 2ecd7b1..d59bc64 100644
--- a/content/browser/indexed_db/indexed_db_dispatcher_host.cc
+++ b/content/browser/indexed_db/indexed_db_dispatcher_host.cc
@@ -237,7 +237,7 @@
 void IndexedDBDispatcherHost::IDBThreadHelper::GetDatabaseNamesOnIDBThread(
     scoped_refptr<IndexedDBCallbacks> callbacks,
     const url::Origin& origin) {
-  DCHECK(indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
+  DCHECK(indexed_db_context_->TaskRunner()->RunsTasksInCurrentSequence());
 
   base::FilePath indexed_db_path = indexed_db_context_->data_path();
   indexed_db_context_->GetIDBFactory()->GetDatabaseNames(
@@ -251,7 +251,7 @@
     const base::string16& name,
     int64_t version,
     int64_t transaction_id) {
-  DCHECK(indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
+  DCHECK(indexed_db_context_->TaskRunner()->RunsTasksInCurrentSequence());
 
   base::TimeTicks begin_time = base::TimeTicks::Now();
   base::FilePath indexed_db_path = indexed_db_context_->data_path();
@@ -274,7 +274,7 @@
     const url::Origin& origin,
     const base::string16& name,
     bool force_close) {
-  DCHECK(indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
+  DCHECK(indexed_db_context_->TaskRunner()->RunsTasksInCurrentSequence());
 
   base::FilePath indexed_db_path = indexed_db_context_->data_path();
   DCHECK(request_context_getter_);
diff --git a/content/browser/indexed_db/indexed_db_internals_ui.cc b/content/browser/indexed_db/indexed_db_internals_ui.cc
index 69aa1539..8e867aae 100644
--- a/content/browser/indexed_db/indexed_db_internals_ui.cc
+++ b/content/browser/indexed_db/indexed_db_internals_ui.cc
@@ -103,7 +103,7 @@
 void IndexedDBInternalsUI::GetAllOriginsOnIndexedDBThread(
     scoped_refptr<IndexedDBContext> context,
     const base::FilePath& context_path) {
-  DCHECK(context->TaskRunner()->RunsTasksOnCurrentThread());
+  DCHECK(context->TaskRunner()->RunsTasksInCurrentSequence());
 
   IndexedDBContextImpl* context_impl =
       static_cast<IndexedDBContextImpl*>(context.get());
@@ -213,7 +213,7 @@
     const base::FilePath& partition_path,
     const scoped_refptr<IndexedDBContextImpl> context,
     const Origin& origin) {
-  DCHECK(context->TaskRunner()->RunsTasksOnCurrentThread());
+  DCHECK(context->TaskRunner()->RunsTasksInCurrentSequence());
   // This runs on the IndexedDB task runner to prevent script from reopening
   // the origin while we are zipping.
 
@@ -251,7 +251,7 @@
     const base::FilePath& partition_path,
     const scoped_refptr<IndexedDBContextImpl> context,
     const Origin& origin) {
-  DCHECK(context->TaskRunner()->RunsTasksOnCurrentThread());
+  DCHECK(context->TaskRunner()->RunsTasksInCurrentSequence());
 
   // Make sure the database hasn't been deleted since the page was loaded.
   if (!context->HasOrigin(origin))
diff --git a/content/browser/indexed_db/indexed_db_quota_client.cc b/content/browser/indexed_db/indexed_db_quota_client.cc
index 894d3612..4215868 100644
--- a/content/browser/indexed_db/indexed_db_quota_client.cc
+++ b/content/browser/indexed_db/indexed_db_quota_client.cc
@@ -30,13 +30,13 @@
 
 int64_t GetOriginUsageOnIndexedDBThread(IndexedDBContextImpl* context,
                                         const GURL& origin) {
-  DCHECK(context->TaskRunner()->RunsTasksOnCurrentThread());
+  DCHECK(context->TaskRunner()->RunsTasksInCurrentSequence());
   return context->GetOriginDiskUsage(origin);
 }
 
 void GetAllOriginsOnIndexedDBThread(IndexedDBContextImpl* context,
                                     std::set<GURL>* origins_to_return) {
-  DCHECK(context->TaskRunner()->RunsTasksOnCurrentThread());
+  DCHECK(context->TaskRunner()->RunsTasksInCurrentSequence());
   for (const auto& origin : context->GetAllOrigins())
     origins_to_return->insert(origin.GetURL());
 }
@@ -50,7 +50,7 @@
 void GetOriginsForHostOnIndexedDBThread(IndexedDBContextImpl* context,
                                         const std::string& host,
                                         std::set<GURL>* origins_to_return) {
-  DCHECK(context->TaskRunner()->RunsTasksOnCurrentThread());
+  DCHECK(context->TaskRunner()->RunsTasksInCurrentSequence());
   for (const auto& origin : context->GetAllOrigins()) {
     GURL origin_url(origin.Serialize());
     if (host == net::GetHostOrSpecFromURL(origin_url))
diff --git a/content/browser/net/quota_policy_cookie_store_unittest.cc b/content/browser/net/quota_policy_cookie_store_unittest.cc
index bc6b243..02c2f9a 100644
--- a/content/browser/net/quota_policy_cookie_store_unittest.cc
+++ b/content/browser/net/quota_policy_cookie_store_unittest.cc
@@ -56,7 +56,7 @@
   }
 
   void ReleaseStore() {
-    EXPECT_TRUE(background_task_runner()->RunsTasksOnCurrentThread());
+    EXPECT_TRUE(background_task_runner()->RunsTasksInCurrentSequence());
     store_ = nullptr;
     destroy_event_.Signal();
   }
diff --git a/content/browser/notifications/platform_notification_context_impl.cc b/content/browser/notifications/platform_notification_context_impl.cc
index 8a15289..9226a44 100644
--- a/content/browser/notifications/platform_notification_context_impl.cc
+++ b/content/browser/notifications/platform_notification_context_impl.cc
@@ -171,7 +171,7 @@
     const std::string& notification_id,
     const GURL& origin,
     const ReadResultCallback& callback) {
-  DCHECK(task_runner_->RunsTasksOnCurrentThread());
+  DCHECK(task_runner_->RunsTasksInCurrentSequence());
 
   NotificationDatabaseData database_data;
   NotificationDatabase::Status status =
@@ -269,7 +269,7 @@
         const ReadAllResultCallback& callback,
         std::unique_ptr<std::set<std::string>> displayed_notifications,
         bool supports_synchronization) {
-  DCHECK(task_runner_->RunsTasksOnCurrentThread());
+  DCHECK(task_runner_->RunsTasksInCurrentSequence());
   DCHECK(displayed_notifications);
 
   std::vector<NotificationDatabaseData> notification_datas;
@@ -333,7 +333,7 @@
     const GURL& origin,
     const NotificationDatabaseData& database_data,
     const WriteResultCallback& callback) {
-  DCHECK(task_runner_->RunsTasksOnCurrentThread());
+  DCHECK(task_runner_->RunsTasksInCurrentSequence());
   DCHECK(database_data.notification_id.empty());
 
   // Eagerly delete data for replaced notifications from the database.
@@ -407,7 +407,7 @@
     const std::string& notification_id,
     const GURL& origin,
     const DeleteResultCallback& callback) {
-  DCHECK(task_runner_->RunsTasksOnCurrentThread());
+  DCHECK(task_runner_->RunsTasksInCurrentSequence());
 
   NotificationDatabase::Status status =
       database_->DeleteNotificationData(notification_id, origin);
@@ -444,7 +444,7 @@
     DoDeleteNotificationsForServiceWorkerRegistration(
         const GURL& origin,
         int64_t service_worker_registration_id) {
-  DCHECK(task_runner_->RunsTasksOnCurrentThread());
+  DCHECK(task_runner_->RunsTasksInCurrentSequence());
 
   std::set<std::string> deleted_notification_ids;
   NotificationDatabase::Status status =
@@ -492,7 +492,7 @@
 void PlatformNotificationContextImpl::OpenDatabase(
     const base::Closure& success_closure,
     const base::Closure& failure_closure) {
-  DCHECK(task_runner_->RunsTasksOnCurrentThread());
+  DCHECK(task_runner_->RunsTasksInCurrentSequence());
 
   if (database_) {
     success_closure.Run();
@@ -542,7 +542,7 @@
 }
 
 bool PlatformNotificationContextImpl::DestroyDatabase() {
-  DCHECK(task_runner_->RunsTasksOnCurrentThread());
+  DCHECK(task_runner_->RunsTasksInCurrentSequence());
   DCHECK(database_);
 
   NotificationDatabase::Status status = database_->Destroy();
diff --git a/content/browser/plugin_private_storage_helper.cc b/content/browser/plugin_private_storage_helper.cc
index a84f6580..c6d19ac 100644
--- a/content/browser/plugin_private_storage_helper.cc
+++ b/content/browser/plugin_private_storage_helper.cc
@@ -281,7 +281,7 @@
 void PluginPrivateDataDeletionHelper::CheckOriginsOnFileTaskRunner(
     const std::set<GURL>& origins) {
   DCHECK(filesystem_context_->default_file_task_runner()
-             ->RunsTasksOnCurrentThread());
+             ->RunsTasksInCurrentSequence());
   IncrementTaskCount();
 
   base::Callback<void(bool, const GURL&)> decrement_callback =
@@ -338,7 +338,7 @@
 
 void PluginPrivateDataDeletionHelper::IncrementTaskCount() {
   DCHECK(filesystem_context_->default_file_task_runner()
-             ->RunsTasksOnCurrentThread());
+             ->RunsTasksInCurrentSequence());
   ++task_count_;
 }
 
@@ -346,7 +346,7 @@
     bool delete_data_for_origin,
     const GURL& origin) {
   DCHECK(filesystem_context_->default_file_task_runner()
-             ->RunsTasksOnCurrentThread());
+             ->RunsTasksInCurrentSequence());
 
   // Since the PluginPrivateDataByOriginChecker runs on the IO thread,
   // delete all the data for |origin| if needed.
@@ -385,7 +385,7 @@
     const base::Time end,
     const base::Closure& callback) {
   DCHECK(filesystem_context->default_file_task_runner()
-             ->RunsTasksOnCurrentThread());
+             ->RunsTasksInCurrentSequence());
   DVLOG(3) << "Clearing plugin data for origin: " << storage_origin;
 
   storage::FileSystemBackend* backend =
diff --git a/content/browser/renderer_host/compositor_impl_android.cc b/content/browser/renderer_host/compositor_impl_android.cc
index 9420ce9d..335a30f3 100644
--- a/content/browser/renderer_host/compositor_impl_android.cc
+++ b/content/browser/renderer_host/compositor_impl_android.cc
@@ -54,6 +54,7 @@
 #include "content/browser/gpu/browser_gpu_memory_buffer_manager.h"
 #include "content/browser/gpu/compositor_util.h"
 #include "content/browser/renderer_host/render_widget_host_impl.h"
+#include "content/common/gpu_stream_constants.h"
 #include "content/public/browser/android/compositor.h"
 #include "content/public/browser/android/compositor_client.h"
 #include "content/public/common/content_switches.h"
@@ -203,12 +204,15 @@
   if (!gpu_channel_host)
     callback.Run(nullptr);
 
+  int32_t stream_id = kGpuStreamIdDefault;
+  gpu::SchedulingPriority stream_priority = kGpuStreamPriorityUI;
+
   constexpr bool automatic_flushes = false;
   constexpr bool support_locking = false;
+
   scoped_refptr<ui::ContextProviderCommandBuffer> context_provider =
       new ui::ContextProviderCommandBuffer(
-          std::move(gpu_channel_host), gpu::GPU_STREAM_DEFAULT,
-          gpu::GpuStreamPriority::NORMAL, handle,
+          std::move(gpu_channel_host), stream_id, stream_priority, handle,
           GURL(std::string("chrome://gpu/Compositor::CreateContextProvider")),
           automatic_flushes, support_locking, shared_memory_limits, attributes,
           nullptr /* shared_context */,
@@ -719,13 +723,18 @@
 
   DCHECK(window_);
   DCHECK_NE(surface_handle_, gpu::kNullSurfaceHandle);
+
+  int32_t stream_id = kGpuStreamIdDefault;
+  gpu::SchedulingPriority stream_priority = kGpuStreamPriorityUI;
+
   constexpr bool support_locking = false;
   constexpr bool automatic_flushes = false;
+
   ui::ContextProviderCommandBuffer* shared_context = nullptr;
   scoped_refptr<ui::ContextProviderCommandBuffer> context_provider =
       new ui::ContextProviderCommandBuffer(
-          std::move(gpu_channel_host), gpu::GPU_STREAM_DEFAULT,
-          gpu::GpuStreamPriority::NORMAL, surface_handle_,
+          std::move(gpu_channel_host), stream_id, stream_priority,
+          surface_handle_,
           GURL(std::string("chrome://gpu/CompositorImpl::") +
                std::string("CompositorContextProvider")),
           automatic_flushes, support_locking,
diff --git a/content/browser/renderer_host/legacy_render_widget_host_win.cc b/content/browser/renderer_host/legacy_render_widget_host_win.cc
index c0eff5b..00f817b 100644
--- a/content/browser/renderer_host/legacy_render_widget_host_win.cc
+++ b/content/browser/renderer_host/legacy_render_widget_host_win.cc
@@ -182,7 +182,7 @@
   BrowserAccessibilityManagerWin* manager =
       static_cast<BrowserAccessibilityManagerWin*>(
           rwhi->GetRootBrowserAccessibilityManager());
-  if (!manager)
+  if (!manager || !manager->GetRoot())
     return static_cast<LRESULT>(0L);
 
   base::win::ScopedComPtr<IAccessible> root(
diff --git a/content/browser/renderer_host/pepper/quota_reservation.cc b/content/browser/renderer_host/pepper/quota_reservation.cc
index 32eb474..2cc4300 100644
--- a/content/browser/renderer_host/pepper/quota_reservation.cc
+++ b/content/browser/renderer_host/pepper/quota_reservation.cc
@@ -134,7 +134,7 @@
 void QuotaReservation::DeleteOnCorrectThread() const {
   if (file_system_context_.get() &&
       !file_system_context_->default_file_task_runner()
-           ->RunsTasksOnCurrentThread()) {
+           ->RunsTasksInCurrentSequence()) {
     file_system_context_->default_file_task_runner()->DeleteSoon(FROM_HERE,
                                                                  this);
   } else {
diff --git a/content/browser/renderer_host/render_widget_host_view_android.cc b/content/browser/renderer_host/render_widget_host_view_android.cc
index 3d5e597..9c5c088 100644
--- a/content/browser/renderer_host/render_widget_host_view_android.cc
+++ b/content/browser/renderer_host/render_widget_host_view_android.cc
@@ -60,6 +60,7 @@
 #include "content/browser/renderer_host/render_view_host_impl.h"
 #include "content/browser/renderer_host/render_widget_host_impl.h"
 #include "content/browser/renderer_host/render_widget_host_input_event_router.h"
+#include "content/common/gpu_stream_constants.h"
 #include "content/common/input_messages.h"
 #include "content/common/site_isolation_policy.h"
 #include "content/common/view_messages.h"
@@ -175,6 +176,9 @@
   if (!gpu_channel_host)
     return;
 
+  int32_t stream_id = kGpuStreamIdDefault;
+  gpu::SchedulingPriority stream_priority = kGpuStreamPriorityUI;
+
   // This is for an offscreen context, so we don't need the default framebuffer
   // to have alpha, stencil, depth, antialiasing.
   gpu::gles2::ContextCreationAttribHelper attributes;
@@ -202,9 +206,9 @@
   const GURL url("chrome://gpu/RenderWidgetHostViewAndroid");
 
   provider_ = new ui::ContextProviderCommandBuffer(
-      std::move(gpu_channel_host), gpu::GPU_STREAM_DEFAULT,
-      gpu::GpuStreamPriority::NORMAL, gpu::kNullSurfaceHandle, url,
-      automatic_flushes, support_locking, limits, attributes, nullptr,
+      std::move(gpu_channel_host), stream_id, stream_priority,
+      gpu::kNullSurfaceHandle, url, automatic_flushes, support_locking, limits,
+      attributes, nullptr,
       ui::command_buffer_metrics::BROWSER_OFFSCREEN_MAINTHREAD_CONTEXT);
   if (!provider_->BindToCurrentThread())
     return;
diff --git a/content/browser/tracing/memory_tracing_browsertest.cc b/content/browser/tracing/memory_tracing_browsertest.cc
index 2e222a85..69ddfa9 100644
--- a/content/browser/tracing/memory_tracing_browsertest.cc
+++ b/content/browser/tracing/memory_tracing_browsertest.cc
@@ -59,7 +59,7 @@
       bool success) {
     // Make sure we run the RunLoop closure on the same thread that originated
     // the run loop (which is the IN_PROC_BROWSER_TEST_F main thread).
-    if (!task_runner->RunsTasksOnCurrentThread()) {
+    if (!task_runner->RunsTasksInCurrentSequence()) {
       task_runner->PostTask(
           FROM_HERE, base::Bind(&MemoryTracingTest::OnGlobalMemoryDumpDone,
                                 base::Unretained(this), task_runner, closure,
diff --git a/content/child/child_message_filter.cc b/content/child/child_message_filter.cc
index 791d901..692c992 100644
--- a/content/child/child_message_filter.cc
+++ b/content/child/child_message_filter.cc
@@ -22,7 +22,7 @@
   bool OnMessageReceived(const IPC::Message& msg) override {
     scoped_refptr<base::TaskRunner> runner =
         filter_->OverrideTaskRunnerForMessage(msg);
-    if (runner.get() && !runner->RunsTasksOnCurrentThread()) {
+    if (runner.get() && !runner->RunsTasksInCurrentSequence()) {
       if (!runner->PostTask(
               FROM_HERE,
               base::Bind(
diff --git a/content/child/fileapi/webfilesystem_impl.cc b/content/child/fileapi/webfilesystem_impl.cc
index cbe1b6f..62204885 100644
--- a/content/child/fileapi/webfilesystem_impl.cc
+++ b/content/child/fileapi/webfilesystem_impl.cc
@@ -97,7 +97,7 @@
     const scoped_refptr<base::SingleThreadTaskRunner>& main_thread_task_runner,
     Method method, const Params& params,
     WaitableCallbackResults* waitable_results) {
-  if (!main_thread_task_runner->RunsTasksOnCurrentThread()) {
+  if (!main_thread_task_runner->RunsTasksInCurrentSequence()) {
     main_thread_task_runner->PostTask(
         FROM_HERE,
         base::Bind(&CallDispatcherOnMainThread<Method, Params>,
diff --git a/content/child/fileapi/webfilewriter_impl.cc b/content/child/fileapi/webfilewriter_impl.cc
index a2f8d92..64583514 100644
--- a/content/child/fileapi/webfilewriter_impl.cc
+++ b/content/child/fileapi/webfilewriter_impl.cc
@@ -162,7 +162,7 @@
 }
 
 void WebFileWriterImpl::RunOnMainThread(const base::Closure& closure) {
-  if (main_thread_task_runner_->RunsTasksOnCurrentThread()) {
+  if (main_thread_task_runner_->RunsTasksInCurrentSequence()) {
     DCHECK(!bridge_->waitable_event());
     closure.Run();
     return;
diff --git a/content/child/service_worker/service_worker_provider_context.cc b/content/child/service_worker/service_worker_provider_context.cc
index bdb318d..9203346 100644
--- a/content/child/service_worker/service_worker_provider_context.cc
+++ b/content/child/service_worker/service_worker_provider_context.cc
@@ -175,21 +175,21 @@
     std::unique_ptr<ServiceWorkerHandleReference> installing,
     std::unique_ptr<ServiceWorkerHandleReference> waiting,
     std::unique_ptr<ServiceWorkerHandleReference> active) {
-  DCHECK(main_thread_task_runner_->RunsTasksOnCurrentThread());
+  DCHECK(main_thread_task_runner_->RunsTasksInCurrentSequence());
   delegate_->AssociateRegistration(std::move(registration),
                                    std::move(installing), std::move(waiting),
                                    std::move(active));
 }
 
 void ServiceWorkerProviderContext::OnDisassociateRegistration() {
-  DCHECK(main_thread_task_runner_->RunsTasksOnCurrentThread());
+  DCHECK(main_thread_task_runner_->RunsTasksInCurrentSequence());
   delegate_->DisassociateRegistration();
 }
 
 void ServiceWorkerProviderContext::OnSetControllerServiceWorker(
     std::unique_ptr<ServiceWorkerHandleReference> controller,
     const std::set<uint32_t>& used_features) {
-  DCHECK(main_thread_task_runner_->RunsTasksOnCurrentThread());
+  DCHECK(main_thread_task_runner_->RunsTasksInCurrentSequence());
   delegate_->SetController(std::move(controller));
   used_features_ = used_features;
 }
@@ -197,7 +197,7 @@
 void ServiceWorkerProviderContext::GetAssociatedRegistration(
     ServiceWorkerRegistrationObjectInfo* info,
     ServiceWorkerVersionAttributes* attrs) {
-  DCHECK(!main_thread_task_runner_->RunsTasksOnCurrentThread());
+  DCHECK(!main_thread_task_runner_->RunsTasksInCurrentSequence());
   delegate_->GetAssociatedRegistration(info, attrs);
 }
 
@@ -206,12 +206,12 @@
 }
 
 ServiceWorkerHandleReference* ServiceWorkerProviderContext::controller() {
-  DCHECK(main_thread_task_runner_->RunsTasksOnCurrentThread());
+  DCHECK(main_thread_task_runner_->RunsTasksInCurrentSequence());
   return delegate_->controller();
 }
 
 void ServiceWorkerProviderContext::DestructOnMainThread() const {
-  if (!main_thread_task_runner_->RunsTasksOnCurrentThread() &&
+  if (!main_thread_task_runner_->RunsTasksInCurrentSequence() &&
       main_thread_task_runner_->DeleteSoon(FROM_HERE, this)) {
     return;
   }
diff --git a/content/child/web_database_observer_impl.cc b/content/child/web_database_observer_impl.cc
index d2d1aa1e..b8eefc6 100644
--- a/content/child/web_database_observer_impl.cc
+++ b/content/child/web_database_observer_impl.cc
@@ -95,7 +95,7 @@
 
 void WebDatabaseObserverImpl::DatabaseClosed(const WebSecurityOrigin& origin,
                                              const WebString& database_name) {
-  DCHECK(!main_thread_task_runner_->RunsTasksOnCurrentThread());
+  DCHECK(!main_thread_task_runner_->RunsTasksInCurrentSequence());
   base::string16 database_name_utf16 = database_name.Utf16();
   main_thread_task_runner_->PostTask(
       FROM_HERE,
@@ -181,7 +181,7 @@
 
 bool WebDatabaseObserverImpl::WaitForAllDatabasesToClose(
     base::TimeDelta timeout) {
-  DCHECK(main_thread_task_runner_->RunsTasksOnCurrentThread());
+  DCHECK(main_thread_task_runner_->RunsTasksInCurrentSequence());
   return open_connections_->WaitForAllDatabasesToClose(timeout);
 }
 
diff --git a/content/common/gpu_stream_constants.h b/content/common/gpu_stream_constants.h
new file mode 100644
index 0000000..f3b0254
--- /dev/null
+++ b/content/common/gpu_stream_constants.h
@@ -0,0 +1,26 @@
+// Copyright (c) 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_COMMON_GPU_STREAM_CONSTANTS_H_
+#define CONTENT_COMMON_GPU_STREAM_CONSTANTS_H_
+
+#include "gpu/command_buffer/common/scheduling_priority.h"
+
+namespace content {
+
+enum {
+  kGpuStreamIdDefault,
+  kGpuStreamIdWorker,
+};
+
+const gpu::SchedulingPriority kGpuStreamPriorityDefault =
+    gpu::SchedulingPriority::kNormal;
+const gpu::SchedulingPriority kGpuStreamPriorityUI =
+    gpu::SchedulingPriority::kHighest;
+const gpu::SchedulingPriority kGpuStreamPriorityWorker =
+    gpu::SchedulingPriority::kLowest;
+
+}  // namespace content
+
+#endif  // CONTENT_COMMON_GPU_STREAM_CONSTANTS_H_
diff --git a/content/public/browser/gpu_utils.cc b/content/public/browser/gpu_utils.cc
index a4145ba..a821ba8 100644
--- a/content/public/browser/gpu_utils.cc
+++ b/content/public/browser/gpu_utils.cc
@@ -55,6 +55,9 @@
       command_line->HasSwitch(switches::kInProcessGPU);
   gpu_preferences.ui_prioritize_in_gpu_process =
       command_line->HasSwitch(switches::kUIPrioritizeInGpuProcess);
+  gpu_preferences.enable_gpu_scheduler =
+      command_line->HasSwitch(switches::kEnableGpuScheduler) &&
+      !command_line->HasSwitch(switches::kDisableGpuScheduler);
   gpu_preferences.disable_accelerated_video_decode =
       command_line->HasSwitch(switches::kDisableAcceleratedVideoDecode);
 #if defined(OS_CHROMEOS)
diff --git a/content/public/common/content_switches.cc b/content/public/common/content_switches.cc
index e1b50f9..c37a3cd 100644
--- a/content/public/common/content_switches.cc
+++ b/content/public/common/content_switches.cc
@@ -174,6 +174,9 @@
 // Disable the GPU process sandbox.
 const char kDisableGpuSandbox[]             = "disable-gpu-sandbox";
 
+// Disable GPU service scheduler.
+const char kDisableGpuScheduler[] = "disable-gpu-scheduler";
+
 // Suppresses hang monitor dialogs in renderer processes.  This may allow slow
 // unload handlers on a page to prevent the tab from closing, but the Task
 // Manager can be used to terminate the offending process in this case.
@@ -390,6 +393,9 @@
     "enabled-slow2g";
 const char kEnableWebFontsInterventionV2SwitchValueDisabled[] = "disabled";
 
+// Enables GPU channel scheduler.
+const char kEnableGpuScheduler[] = "enable-gpu-scheduler";
+
 // Makes the GL worker context run asynchronously by using a separate stream.
 const char kEnableGpuAsyncWorkerContext[] = "enable-gpu-async-worker-context";
 
diff --git a/content/public/common/content_switches.h b/content/public/common/content_switches.h
index dacbdc9871..7a4b891 100644
--- a/content/public/common/content_switches.h
+++ b/content/public/common/content_switches.h
@@ -60,6 +60,7 @@
 CONTENT_EXPORT extern const char kDisableGpuMemoryBufferVideoFrames[];
 extern const char kDisableGpuProcessCrashLimit[];
 CONTENT_EXPORT extern const char kDisableGpuSandbox[];
+CONTENT_EXPORT extern const char kDisableGpuScheduler[];
 CONTENT_EXPORT extern const char kDisableJavaScriptHarmonyShipping[];
 CONTENT_EXPORT extern const char kDisableLowLatencyDxva[];
 CONTENT_EXPORT extern const char kDisableLowResTiling[];
@@ -125,6 +126,7 @@
     kEnableWebFontsInterventionV2SwitchValueEnabledWithSlow2G[];
 CONTENT_EXPORT extern const char
     kEnableWebFontsInterventionV2SwitchValueDisabled[];
+CONTENT_EXPORT extern const char kEnableGpuScheduler[];
 CONTENT_EXPORT extern const char kEnableGpuAsyncWorkerContext[];
 CONTENT_EXPORT extern const char kEnableGpuMemoryBufferCompositorResources[];
 CONTENT_EXPORT extern const char kEnableGpuMemoryBufferVideoFrames[];
diff --git a/content/public/test/test_browser_thread.cc b/content/public/test/test_browser_thread.cc
index 54db895..2efe692 100644
--- a/content/public/test/test_browser_thread.cc
+++ b/content/public/test/test_browser_thread.cc
@@ -59,7 +59,7 @@
   // been flushed and deleted in Stop(). In the case of an externally provided
   // MessageLoop however, this means that TaskRunners obtained through
   // |BrowserThreadImpl::GetTaskRunnerForThread(identifier_)| will no longer
-  // recognize their BrowserThreadImpl for RunsTasksOnCurrentThread(). This
+  // recognize their BrowserThreadImpl for RunsTasksInCurrentSequence(). This
   // happens most often when such verifications are made from
   // MessageLoop::DestructionObservers. Callers that care to work around that
   // should instead use this shutdown sequence:
diff --git a/content/renderer/media/media_permission_dispatcher.cc b/content/renderer/media/media_permission_dispatcher.cc
index efe570e..31bda16 100644
--- a/content/renderer/media/media_permission_dispatcher.cc
+++ b/content/renderer/media/media_permission_dispatcher.cc
@@ -53,7 +53,7 @@
 }
 
 MediaPermissionDispatcher::~MediaPermissionDispatcher() {
-  DCHECK(task_runner_->RunsTasksOnCurrentThread());
+  DCHECK(task_runner_->RunsTasksInCurrentSequence());
 
   // Fire all pending callbacks with |false|.
   for (auto& request : requests_)
@@ -64,7 +64,7 @@
     Type type,
     const GURL& security_origin,
     const PermissionStatusCB& permission_status_cb) {
-  if (!task_runner_->RunsTasksOnCurrentThread()) {
+  if (!task_runner_->RunsTasksInCurrentSequence()) {
     task_runner_->PostTask(
         FROM_HERE, base::Bind(&MediaPermissionDispatcher::HasPermission,
                               weak_ptr_, type, security_origin,
@@ -72,7 +72,7 @@
     return;
   }
 
-  DCHECK(task_runner_->RunsTasksOnCurrentThread());
+  DCHECK(task_runner_->RunsTasksInCurrentSequence());
 
   if (!permission_service_)
     connect_to_service_cb_.Run(mojo::MakeRequest(&permission_service_));
@@ -91,7 +91,7 @@
     Type type,
     const GURL& security_origin,
     const PermissionStatusCB& permission_status_cb) {
-  if (!task_runner_->RunsTasksOnCurrentThread()) {
+  if (!task_runner_->RunsTasksInCurrentSequence()) {
     task_runner_->PostTask(
         FROM_HERE, base::Bind(&MediaPermissionDispatcher::RequestPermission,
                               weak_ptr_, type, security_origin,
@@ -99,7 +99,7 @@
     return;
   }
 
-  DCHECK(task_runner_->RunsTasksOnCurrentThread());
+  DCHECK(task_runner_->RunsTasksInCurrentSequence());
 
   if (!permission_service_)
     connect_to_service_cb_.Run(mojo::MakeRequest(&permission_service_));
@@ -117,7 +117,7 @@
 
 uint32_t MediaPermissionDispatcher::RegisterCallback(
     const PermissionStatusCB& permission_status_cb) {
-  DCHECK(task_runner_->RunsTasksOnCurrentThread());
+  DCHECK(task_runner_->RunsTasksInCurrentSequence());
 
   uint32_t request_id = next_request_id_++;
   DCHECK(!requests_.count(request_id));
@@ -130,7 +130,7 @@
     uint32_t request_id,
     blink::mojom::PermissionStatus status) {
   DVLOG(2) << __func__ << ": (" << request_id << ", " << status << ")";
-  DCHECK(task_runner_->RunsTasksOnCurrentThread());
+  DCHECK(task_runner_->RunsTasksInCurrentSequence());
 
   RequestMap::iterator iter = requests_.find(request_id);
   DCHECK(iter != requests_.end()) << "Request not found.";
diff --git a/content/renderer/media/media_stream_audio_source.cc b/content/renderer/media/media_stream_audio_source.cc
index e1b7e5ed..be556185 100644
--- a/content/renderer/media/media_stream_audio_source.cc
+++ b/content/renderer/media/media_stream_audio_source.cc
@@ -23,7 +23,7 @@
 }
 
 MediaStreamAudioSource::~MediaStreamAudioSource() {
-  DCHECK(task_runner_->RunsTasksOnCurrentThread());
+  DCHECK(task_runner_->RunsTasksInCurrentSequence());
   DVLOG(1) << "MediaStreamAudioSource@" << this << " is being destroyed.";
 }
 
@@ -39,7 +39,7 @@
 
 bool MediaStreamAudioSource::ConnectToTrack(
     const blink::WebMediaStreamTrack& blink_track) {
-  DCHECK(task_runner_->RunsTasksOnCurrentThread());
+  DCHECK(task_runner_->RunsTasksInCurrentSequence());
   DCHECK(!blink_track.IsNull());
 
   // Sanity-check that there is not already a MediaStreamAudioTrack instance
@@ -91,19 +91,19 @@
 
 std::unique_ptr<MediaStreamAudioTrack>
 MediaStreamAudioSource::CreateMediaStreamAudioTrack(const std::string& id) {
-  DCHECK(task_runner_->RunsTasksOnCurrentThread());
+  DCHECK(task_runner_->RunsTasksInCurrentSequence());
   return std::unique_ptr<MediaStreamAudioTrack>(
       new MediaStreamAudioTrack(is_local_source()));
 }
 
 bool MediaStreamAudioSource::EnsureSourceIsStarted() {
-  DCHECK(task_runner_->RunsTasksOnCurrentThread());
+  DCHECK(task_runner_->RunsTasksInCurrentSequence());
   DVLOG(1) << "MediaStreamAudioSource@" << this << "::EnsureSourceIsStarted()";
   return true;
 }
 
 void MediaStreamAudioSource::EnsureSourceIsStopped() {
-  DCHECK(task_runner_->RunsTasksOnCurrentThread());
+  DCHECK(task_runner_->RunsTasksInCurrentSequence());
   DVLOG(1) << "MediaStreamAudioSource@" << this << "::EnsureSourceIsStopped()";
 }
 
@@ -121,13 +121,13 @@
 }
 
 void MediaStreamAudioSource::DoStopSource() {
-  DCHECK(task_runner_->RunsTasksOnCurrentThread());
+  DCHECK(task_runner_->RunsTasksInCurrentSequence());
   EnsureSourceIsStopped();
   is_stopped_ = true;
 }
 
 void MediaStreamAudioSource::StopAudioDeliveryTo(MediaStreamAudioTrack* track) {
-  DCHECK(task_runner_->RunsTasksOnCurrentThread());
+  DCHECK(task_runner_->RunsTasksInCurrentSequence());
 
   const bool did_remove_last_track = deliverer_.RemoveConsumer(track);
   DVLOG(1) << "Removed MediaStreamAudioTrack@" << track
diff --git a/content/renderer/media/webmediaplayer_ms.cc b/content/renderer/media/webmediaplayer_ms.cc
index 2b450c9..9525264 100644
--- a/content/renderer/media/webmediaplayer_ms.cc
+++ b/content/renderer/media/webmediaplayer_ms.cc
@@ -577,10 +577,12 @@
 
 bool WebMediaPlayerMS::CopyVideoTextureToPlatformTexture(
     gpu::gles2::GLES2Interface* gl,
+    unsigned target,
     unsigned int texture,
     unsigned internal_format,
     unsigned format,
     unsigned type,
+    int level,
     bool premultiply_alpha,
     bool flip_y) {
   TRACE_EVENT0("media", "WebMediaPlayerMS:copyVideoTextureToPlatformTexture");
@@ -601,8 +603,8 @@
   context_3d = media::Context3D(provider->ContextGL(), provider->GrContext());
   DCHECK(context_3d.gl);
   return video_renderer_.CopyVideoFrameTexturesToGLTexture(
-      context_3d, gl, video_frame.get(), texture, internal_format, format, type,
-      premultiply_alpha, flip_y);
+      context_3d, gl, video_frame.get(), target, texture, internal_format,
+      format, type, level, premultiply_alpha, flip_y);
 }
 
 bool WebMediaPlayerMS::TexImageImpl(TexImageFunctionID functionID,
diff --git a/content/renderer/media/webmediaplayer_ms.h b/content/renderer/media/webmediaplayer_ms.h
index d171aea..55d8028 100644
--- a/content/renderer/media/webmediaplayer_ms.h
+++ b/content/renderer/media/webmediaplayer_ms.h
@@ -153,10 +153,12 @@
   void OnBecamePersistentVideo(bool value) override;
 
   bool CopyVideoTextureToPlatformTexture(gpu::gles2::GLES2Interface* gl,
+                                         unsigned target,
                                          unsigned int texture,
                                          unsigned internal_format,
                                          unsigned format,
                                          unsigned type,
+                                         int level,
                                          bool premultiply_alpha,
                                          bool flip_y) override;
 
diff --git a/content/renderer/media/webrtc/webrtc_audio_sink.cc b/content/renderer/media/webrtc/webrtc_audio_sink.cc
index 2d789a9a..dff9ff3 100644
--- a/content/renderer/media/webrtc/webrtc_audio_sink.cc
+++ b/content/renderer/media/webrtc/webrtc_audio_sink.cc
@@ -139,14 +139,14 @@
 
 bool WebRtcAudioSink::Adapter::set_enabled(bool enable) {
   DCHECK(!signaling_task_runner_ ||
-         signaling_task_runner_->RunsTasksOnCurrentThread());
+         signaling_task_runner_->RunsTasksInCurrentSequence());
   return webrtc::MediaStreamTrack<webrtc::AudioTrackInterface>::
       set_enabled(enable);
 }
 
 void WebRtcAudioSink::Adapter::AddSink(webrtc::AudioTrackSinkInterface* sink) {
   DCHECK(!signaling_task_runner_ ||
-         signaling_task_runner_->RunsTasksOnCurrentThread());
+         signaling_task_runner_->RunsTasksInCurrentSequence());
   DCHECK(sink);
   base::AutoLock auto_lock(lock_);
   DCHECK(std::find(sinks_.begin(), sinks_.end(), sink) == sinks_.end());
@@ -156,7 +156,7 @@
 void WebRtcAudioSink::Adapter::RemoveSink(
     webrtc::AudioTrackSinkInterface* sink) {
   DCHECK(!signaling_task_runner_ ||
-         signaling_task_runner_->RunsTasksOnCurrentThread());
+         signaling_task_runner_->RunsTasksInCurrentSequence());
   base::AutoLock auto_lock(lock_);
   const auto it = std::find(sinks_.begin(), sinks_.end(), sink);
   if (it != sinks_.end())
@@ -165,7 +165,7 @@
 
 bool WebRtcAudioSink::Adapter::GetSignalLevel(int* level) {
   DCHECK(!signaling_task_runner_ ||
-         signaling_task_runner_->RunsTasksOnCurrentThread());
+         signaling_task_runner_->RunsTasksInCurrentSequence());
 
   // |level_| is only set once, so it's safe to read without first acquiring a
   // mutex.
@@ -183,13 +183,13 @@
 rtc::scoped_refptr<webrtc::AudioProcessorInterface>
 WebRtcAudioSink::Adapter::GetAudioProcessor() {
   DCHECK(!signaling_task_runner_ ||
-         signaling_task_runner_->RunsTasksOnCurrentThread());
+         signaling_task_runner_->RunsTasksInCurrentSequence());
   return audio_processor_.get();
 }
 
 webrtc::AudioSourceInterface* WebRtcAudioSink::Adapter::GetSource() const {
   DCHECK(!signaling_task_runner_ ||
-         signaling_task_runner_->RunsTasksOnCurrentThread());
+         signaling_task_runner_->RunsTasksInCurrentSequence());
   return source_.get();
 }
 
diff --git a/content/renderer/pepper/pepper_video_encoder_host.cc b/content/renderer/pepper/pepper_video_encoder_host.cc
index 35838430..4f55b433 100644
--- a/content/renderer/pepper/pepper_video_encoder_host.cc
+++ b/content/renderer/pepper/pepper_video_encoder_host.cc
@@ -12,6 +12,7 @@
 #include "base/numerics/safe_math.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "build/build_config.h"
+#include "content/common/gpu_stream_constants.h"
 #include "content/common/pepper_file_util.h"
 #include "content/public/renderer/renderer_ppapi_host.h"
 #include "content/renderer/pepper/gfx_conversion.h"
@@ -530,10 +531,9 @@
     return false;
 
   command_buffer_ = gpu::CommandBufferProxyImpl::Create(
-      std::move(channel), gpu::kNullSurfaceHandle, nullptr,
-      gpu::GPU_STREAM_DEFAULT, gpu::GpuStreamPriority::NORMAL,
-      gpu::gles2::ContextCreationAttribHelper(), GURL::EmptyGURL(),
-      base::ThreadTaskRunnerHandle::Get());
+      std::move(channel), gpu::kNullSurfaceHandle, nullptr, kGpuStreamIdDefault,
+      kGpuStreamPriorityDefault, gpu::gles2::ContextCreationAttribHelper(),
+      GURL::EmptyGURL(), base::ThreadTaskRunnerHandle::Get());
   if (!command_buffer_) {
     Close();
     return false;
diff --git a/content/renderer/pepper/ppb_graphics_3d_impl.cc b/content/renderer/pepper/ppb_graphics_3d_impl.cc
index 77102f2..53f7da9c 100644
--- a/content/renderer/pepper/ppb_graphics_3d_impl.cc
+++ b/content/renderer/pepper/ppb_graphics_3d_impl.cc
@@ -12,6 +12,7 @@
 #include "base/single_thread_task_runner.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/threading/thread_task_runner_handle.h"
+#include "content/common/gpu_stream_constants.h"
 #include "content/public/common/content_features.h"
 #include "content/public/common/content_switches.h"
 #include "content/public/common/web_preferences.h"
@@ -257,7 +258,7 @@
 
   command_buffer_ = gpu::CommandBufferProxyImpl::Create(
       std::move(channel), gpu::kNullSurfaceHandle, share_buffer,
-      gpu::GPU_STREAM_DEFAULT, gpu::GpuStreamPriority::NORMAL, attrib_helper,
+      kGpuStreamIdDefault, kGpuStreamPriorityDefault, attrib_helper,
       GURL::EmptyGURL(), base::ThreadTaskRunnerHandle::Get());
   if (!command_buffer_)
     return false;
diff --git a/content/renderer/render_thread_impl.cc b/content/renderer/render_thread_impl.cc
index 0ef51fc..a56d9d8 100644
--- a/content/renderer/render_thread_impl.cc
+++ b/content/renderer/render_thread_impl.cc
@@ -75,6 +75,7 @@
 #include "content/common/field_trial_recorder.mojom.h"
 #include "content/common/frame_messages.h"
 #include "content/common/frame_owner_properties.h"
+#include "content/common/gpu_stream_constants.h"
 #include "content/common/render_process_messages.h"
 #include "content/common/resource_messages.h"
 #include "content/common/site_isolation_policy.h"
@@ -366,7 +367,7 @@
     bool support_locking,
     ui::command_buffer_metrics::ContextType type,
     int32_t stream_id,
-    gpu::GpuStreamPriority stream_priority) {
+    gpu::SchedulingPriority stream_priority) {
   DCHECK(gpu_channel_host);
   // This is used to create a few different offscreen contexts:
   // - The shared main thread context (offscreen) used by blink for canvas.
@@ -1396,8 +1397,7 @@
   scoped_refptr<ui::ContextProviderCommandBuffer> media_context_provider =
       CreateOffscreenContext(gpu_channel_host, limits, support_locking,
                              ui::command_buffer_metrics::MEDIA_CONTEXT,
-                             gpu::GPU_STREAM_DEFAULT,
-                             gpu::GpuStreamPriority::NORMAL);
+                             kGpuStreamIdDefault, kGpuStreamPriorityDefault);
   if (!media_context_provider->BindToCurrentThread())
     return nullptr;
 
@@ -1447,7 +1447,7 @@
   shared_main_thread_contexts_ = CreateOffscreenContext(
       std::move(gpu_channel_host), gpu::SharedMemoryLimits(), support_locking,
       ui::command_buffer_metrics::RENDERER_MAINTHREAD_CONTEXT,
-      gpu::GPU_STREAM_DEFAULT, gpu::GpuStreamPriority::NORMAL);
+      kGpuStreamIdDefault, kGpuStreamPriorityDefault);
   if (!shared_main_thread_contexts_->BindToCurrentThread())
     shared_main_thread_contexts_ = nullptr;
   return shared_main_thread_contexts_;
@@ -1960,9 +1960,9 @@
 
   scoped_refptr<ui::ContextProviderCommandBuffer> context_provider(
       new ui::ContextProviderCommandBuffer(
-          gpu_channel_host, gpu::GPU_STREAM_DEFAULT,
-          gpu::GpuStreamPriority::NORMAL, gpu::kNullSurfaceHandle, url,
-          automatic_flushes, support_locking, limits, attributes, share_context,
+          gpu_channel_host, kGpuStreamIdDefault, kGpuStreamPriorityDefault,
+          gpu::kNullSurfaceHandle, url, automatic_flushes, support_locking,
+          limits, attributes, share_context,
           ui::command_buffer_metrics::RENDER_COMPOSITOR_CONTEXT));
 
   if (layout_test_deps_) {
@@ -2303,11 +2303,11 @@
     return shared_worker_context_provider_;
   }
 
-  int32_t stream_id = gpu::GPU_STREAM_DEFAULT;
-  gpu::GpuStreamPriority stream_priority = gpu::GpuStreamPriority::NORMAL;
+  int32_t stream_id = kGpuStreamIdDefault;
+  gpu::SchedulingPriority stream_priority = kGpuStreamPriorityDefault;
   if (is_async_worker_context_enabled_) {
-    stream_id = gpu_channel_host->GenerateStreamID();
-    stream_priority = gpu::GpuStreamPriority::LOW;
+    stream_id = kGpuStreamIdWorker;
+    stream_priority = kGpuStreamPriorityWorker;
   }
 
   bool support_locking = true;
diff --git a/content/renderer/renderer_blink_platform_impl.cc b/content/renderer/renderer_blink_platform_impl.cc
index 5389c9d..cd57d58 100644
--- a/content/renderer/renderer_blink_platform_impl.cc
+++ b/content/renderer/renderer_blink_platform_impl.cc
@@ -39,6 +39,7 @@
 #include "content/child/webmessageportchannel_impl.h"
 #include "content/common/file_utilities_messages.h"
 #include "content/common/frame_messages.h"
+#include "content/common/gpu_stream_constants.h"
 #include "content/common/render_process_messages.h"
 #include "content/public/common/content_switches.h"
 #include "content/public/common/service_manager_connection.h"
@@ -72,7 +73,6 @@
 #include "gpu/command_buffer/client/gles2_interface.h"
 #include "gpu/config/gpu_info.h"
 #include "gpu/ipc/client/gpu_channel_host.h"
-#include "gpu/ipc/common/gpu_stream_constants.h"
 #include "ipc/ipc_sync_message_filter.h"
 #include "media/audio/audio_output_device.h"
 #include "media/blink/webcontentdecryptionmodule_impl.h"
@@ -1041,8 +1041,8 @@
 
   scoped_refptr<ui::ContextProviderCommandBuffer> provider(
       new ui::ContextProviderCommandBuffer(
-          std::move(gpu_channel_host), gpu::GPU_STREAM_DEFAULT,
-          gpu::GpuStreamPriority::NORMAL, gpu::kNullSurfaceHandle,
+          std::move(gpu_channel_host), kGpuStreamIdDefault,
+          kGpuStreamPriorityDefault, gpu::kNullSurfaceHandle,
           GURL(top_document_web_url), automatic_flushes, support_locking,
           gpu::SharedMemoryLimits(), attributes, share_context,
           ui::command_buffer_metrics::OFFSCREEN_CONTEXT_FOR_WEBGL));
diff --git a/content/renderer/service_worker/service_worker_context_client.cc b/content/renderer/service_worker/service_worker_context_client.cc
index f0b2141..33410ae 100644
--- a/content/renderer/service_worker/service_worker_context_client.cc
+++ b/content/renderer/service_worker/service_worker_context_client.cc
@@ -650,12 +650,12 @@
 }
 
 void ServiceWorkerContextClient::WorkerReadyForInspection() {
-  DCHECK(main_thread_task_runner_->RunsTasksOnCurrentThread());
+  DCHECK(main_thread_task_runner_->RunsTasksInCurrentSequence());
   (*instance_host_)->OnReadyForInspection();
 }
 
 void ServiceWorkerContextClient::WorkerContextFailedToStart() {
-  DCHECK(main_thread_task_runner_->RunsTasksOnCurrentThread());
+  DCHECK(main_thread_task_runner_->RunsTasksInCurrentSequence());
   DCHECK(!proxy_);
 
   (*instance_host_)->OnScriptLoadFailed();
@@ -666,7 +666,7 @@
 }
 
 void ServiceWorkerContextClient::WorkerScriptLoaded() {
-  DCHECK(main_thread_task_runner_->RunsTasksOnCurrentThread());
+  DCHECK(main_thread_task_runner_->RunsTasksInCurrentSequence());
   DCHECK(!proxy_);
 
   (*instance_host_)->OnScriptLoaded();
@@ -719,7 +719,7 @@
 }
 
 void ServiceWorkerContextClient::DidEvaluateWorkerScript(bool success) {
-  DCHECK(worker_task_runner_->RunsTasksOnCurrentThread());
+  DCHECK(worker_task_runner_->RunsTasksInCurrentSequence());
   (*instance_host_)->OnScriptEvaluated(success);
 
   // Schedule a task to send back WorkerStarted asynchronously,
@@ -741,7 +741,7 @@
 void ServiceWorkerContextClient::WillDestroyWorkerContext(
     v8::Local<v8::Context> context) {
   // At this point WillStopCurrentWorkerThread is already called, so
-  // worker_task_runner_->RunsTasksOnCurrentThread() returns false
+  // worker_task_runner_->RunsTasksInCurrentSequence() returns false
   // (while we're still on the worker thread).
   proxy_ = NULL;
 
@@ -1083,7 +1083,7 @@
 
 std::unique_ptr<blink::WebServiceWorkerNetworkProvider>
 ServiceWorkerContextClient::CreateServiceWorkerNetworkProvider() {
-  DCHECK(main_thread_task_runner_->RunsTasksOnCurrentThread());
+  DCHECK(main_thread_task_runner_->RunsTasksInCurrentSequence());
 
   // Create a content::ServiceWorkerNetworkProvider for this data source so
   // we can observe its requests.
@@ -1105,7 +1105,7 @@
 
 std::unique_ptr<blink::WebWorkerFetchContext>
 ServiceWorkerContextClient::CreateServiceWorkerFetchContext() {
-  DCHECK(main_thread_task_runner_->RunsTasksOnCurrentThread());
+  DCHECK(main_thread_task_runner_->RunsTasksInCurrentSequence());
   DCHECK(base::FeatureList::IsEnabled(features::kOffMainThreadFetch));
   mojom::WorkerURLLoaderFactoryProviderPtr worker_url_loader_factory_provider;
   RenderThreadImpl::current()
@@ -1120,7 +1120,7 @@
 
 std::unique_ptr<blink::WebServiceWorkerProvider>
 ServiceWorkerContextClient::CreateServiceWorkerProvider() {
-  DCHECK(main_thread_task_runner_->RunsTasksOnCurrentThread());
+  DCHECK(main_thread_task_runner_->RunsTasksInCurrentSequence());
   DCHECK(provider_context_);
 
   // Blink is responsible for deleting the returned object.
@@ -1222,7 +1222,7 @@
 }
 
 void ServiceWorkerContextClient::SendWorkerStarted() {
-  DCHECK(worker_task_runner_->RunsTasksOnCurrentThread());
+  DCHECK(worker_task_runner_->RunsTasksInCurrentSequence());
   TRACE_EVENT_ASYNC_END0("ServiceWorker",
                          "ServiceWorkerContextClient::StartingWorkerContext",
                          this);
@@ -1232,7 +1232,7 @@
 void ServiceWorkerContextClient::SetRegistrationInServiceWorkerGlobalScope(
     const ServiceWorkerRegistrationObjectInfo& info,
     const ServiceWorkerVersionAttributes& attrs) {
-  DCHECK(worker_task_runner_->RunsTasksOnCurrentThread());
+  DCHECK(worker_task_runner_->RunsTasksInCurrentSequence());
   ServiceWorkerDispatcher* dispatcher =
       ServiceWorkerDispatcher::GetOrCreateThreadSpecificInstance(
           sender_.get(), main_thread_task_runner_.get());
@@ -1686,7 +1686,7 @@
 
 base::WeakPtr<ServiceWorkerContextClient>
 ServiceWorkerContextClient::GetWeakPtr() {
-  DCHECK(worker_task_runner_->RunsTasksOnCurrentThread());
+  DCHECK(worker_task_runner_->RunsTasksInCurrentSequence());
   DCHECK(context_);
   return context_->weak_factory.GetWeakPtr();
 }
diff --git a/content/renderer/service_worker/worker_fetch_context_impl.cc b/content/renderer/service_worker/worker_fetch_context_impl.cc
index f204642..bba1ed6d 100644
--- a/content/renderer/service_worker/worker_fetch_context_impl.cc
+++ b/content/renderer/service_worker/worker_fetch_context_impl.cc
@@ -19,7 +19,7 @@
 
 void WorkerFetchContextImpl::InitializeOnWorkerThread(
     base::SingleThreadTaskRunner* loading_task_runner) {
-  DCHECK(loading_task_runner->RunsTasksOnCurrentThread());
+  DCHECK(loading_task_runner->RunsTasksInCurrentSequence());
   DCHECK(!resource_dispatcher_);
   DCHECK(!binding_);
   resource_dispatcher_ =
diff --git a/content/shell/browser/layout_test/layout_test_bluetooth_adapter_provider.cc b/content/shell/browser/layout_test/layout_test_bluetooth_adapter_provider.cc
index 77f0c903..c354abe 100644
--- a/content/shell/browser/layout_test/layout_test_bluetooth_adapter_provider.cc
+++ b/content/shell/browser/layout_test/layout_test_bluetooth_adapter_provider.cc
@@ -182,18 +182,12 @@
     return GetFailStartDiscoveryAdapter();
   if (fake_adapter_name == "GlucoseHeartRateAdapter")
     return GetGlucoseHeartRateAdapter();
-  if (fake_adapter_name == "UnicodeDeviceAdapter")
-    return GetUnicodeDeviceAdapter();
-  if (fake_adapter_name == "DeviceNameLongerThan29BytesAdapter")
-    return GetDeviceNameLongerThan29BytesAdapter();
   if (fake_adapter_name == "MissingServiceHeartRateAdapter")
     return GetMissingServiceHeartRateAdapter();
   if (fake_adapter_name == "MissingCharacteristicHeartRateAdapter")
     return GetMissingCharacteristicHeartRateAdapter();
   if (fake_adapter_name == "HeartRateAdapter")
     return GetHeartRateAdapter();
-  if (fake_adapter_name == "EmptyNameDeviceAdapter")
-    return GetEmptyNameDeviceAdapter();
   if (fake_adapter_name == "NoNameDeviceAdapter")
     return GetNoNameDeviceAdapter();
   if (fake_adapter_name == "EmptyNameHeartRateAdapter")
@@ -380,27 +374,6 @@
   return adapter;
 }
 
-// static
-scoped_refptr<NiceMockBluetoothAdapter>
-LayoutTestBluetoothAdapterProvider::GetUnicodeDeviceAdapter() {
-  scoped_refptr<NiceMockBluetoothAdapter> adapter(GetEmptyAdapter());
-
-  adapter->AddMockDevice(GetBaseDevice(adapter.get(), "❤❤❤❤❤❤❤❤❤"));
-
-  return adapter;
-}
-
-// static
-scoped_refptr<NiceMockBluetoothAdapter>
-LayoutTestBluetoothAdapterProvider::GetDeviceNameLongerThan29BytesAdapter() {
-  scoped_refptr<NiceMockBluetoothAdapter> adapter(GetEmptyAdapter());
-
-  adapter->AddMockDevice(GetBaseDevice(adapter.get(),
-                         "a_device_name_that_is_longer_than_29_bytes_but_shorter_than_248_bytes"));
-
-  return adapter;
-}
-
 // Adds a device to |adapter| and notifies all observers about that new device.
 // Mocks can call this asynchronously to cause changes in the middle of a test.
 static void AddDevice(scoped_refptr<NiceMockBluetoothAdapter> adapter,
@@ -768,16 +741,6 @@
 
 // static
 scoped_refptr<NiceMockBluetoothAdapter>
-LayoutTestBluetoothAdapterProvider::GetEmptyNameDeviceAdapter() {
-  scoped_refptr<NiceMockBluetoothAdapter> adapter(GetEmptyAdapter());
-  auto device(GetConnectableDevice(adapter.get(), "" /* device_name */));
-
-  adapter->AddMockDevice(std::move(device));
-  return adapter;
-}
-
-// static
-scoped_refptr<NiceMockBluetoothAdapter>
 LayoutTestBluetoothAdapterProvider::GetNoNameDeviceAdapter() {
   scoped_refptr<NiceMockBluetoothAdapter> adapter(GetEmptyAdapter());
   auto device(GetConnectableDevice(adapter.get(), nullptr /* device_name */));
diff --git a/content/shell/browser/layout_test/layout_test_bluetooth_adapter_provider.h b/content/shell/browser/layout_test/layout_test_bluetooth_adapter_provider.h
index 346bea2..46176d8 100644
--- a/content/shell/browser/layout_test/layout_test_bluetooth_adapter_provider.h
+++ b/content/shell/browser/layout_test/layout_test_bluetooth_adapter_provider.h
@@ -107,24 +107,6 @@
   static scoped_refptr<testing::NiceMock<device::MockBluetoothAdapter>>
   GetGlucoseHeartRateAdapter();
 
-  // |GetUnicodeDeviceAdapter|
-  // Inherits from |EmptyAdapter|
-  // Internal structure
-  //  - UnicodeDevice
-  //    - Mock Functions:
-  //      - GetName(): Returns "❤❤❤❤❤❤❤❤❤"
-  static scoped_refptr<testing::NiceMock<device::MockBluetoothAdapter>>
-  GetUnicodeDeviceAdapter();
-
-  // |GetDeviceNameLongerThan29BytesAdapter|
-  // Inherits from |EmptyAdapter|
-  // Internal structure
-  //  - DeviceNameLongerThan29Bytes
-  //    - Mock Functions:
-  //      - GetName(): Returns "a_device_name_that_is_longer_than_29_bytes_but_shorter_than_248_bytes"
-  static scoped_refptr<testing::NiceMock<device::MockBluetoothAdapter>>
-  GetDeviceNameLongerThan29BytesAdapter();
-
   // |SecondDiscoveryFindsHeartRateAdapter|
   // Inherits from |PoweredAdapter|
   // Mock Functions:
@@ -224,12 +206,6 @@
   static scoped_refptr<testing::NiceMock<device::MockBluetoothAdapter>>
   GetHeartRateAdapter();
 
-  // |GetEmptyNameDeviceAdapter|
-  // Inherits from |EmptyAdapter|
-  // Contains a single device with an empty name and no UUIDs.
-  static scoped_refptr<testing::NiceMock<device::MockBluetoothAdapter>>
-  GetEmptyNameDeviceAdapter();
-
   // |GetNoNameDeviceAdapter|
   // Inherits from |EmptyAdapter|
   // Contains a single device with no name and no UUIDs.
diff --git a/content/test/layouttest_support.cc b/content/test/layouttest_support.cc
index 3896c9b8..8ddd1ba0 100644
--- a/content/test/layouttest_support.cc
+++ b/content/test/layouttest_support.cc
@@ -20,6 +20,7 @@
 #include "content/browser/renderer_host/render_process_host_impl.h"
 #include "content/browser/renderer_host/render_widget_host_impl.h"
 #include "content/child/request_extra_data.h"
+#include "content/common/gpu_stream_constants.h"
 #include "content/common/renderer.mojom.h"
 #include "content/public/common/page_state.h"
 #include "content/public/common/screen_info.h"
@@ -391,8 +392,8 @@
 
     auto context_provider =
         make_scoped_refptr(new ui::ContextProviderCommandBuffer(
-            gpu_channel_, gpu::GPU_STREAM_DEFAULT,
-            gpu::GpuStreamPriority::NORMAL, gpu::kNullSurfaceHandle,
+            gpu_channel_, kGpuStreamIdDefault, kGpuStreamPriorityDefault,
+            gpu::kNullSurfaceHandle,
             GURL("chrome://gpu/"
                  "LayoutTestDependenciesImpl::CreateOutputSurface"),
             automatic_flushes, support_locking, gpu::SharedMemoryLimits(),
diff --git a/device/bluetooth/BUILD.gn b/device/bluetooth/BUILD.gn
index 2652d4f..f4e2b6c 100644
--- a/device/bluetooth/BUILD.gn
+++ b/device/bluetooth/BUILD.gn
@@ -47,6 +47,8 @@
     "test/fake_bluetooth.h",
     "test/fake_central.cc",
     "test/fake_central.h",
+    "test/fake_peripheral.cc",
+    "test/fake_peripheral.h",
   ]
 
   deps = [
diff --git a/device/bluetooth/public/interfaces/BUILD.gn b/device/bluetooth/public/interfaces/BUILD.gn
index 5e7d9c7..4ef85b8 100644
--- a/device/bluetooth/public/interfaces/BUILD.gn
+++ b/device/bluetooth/public/interfaces/BUILD.gn
@@ -14,6 +14,12 @@
   sources = [
     "test/fake_bluetooth.mojom",
   ]
+
+  public_deps = [
+    ":interfaces",
+  ]
+
+  use_once_callback = true
 }
 
 mojom("experimental_interfaces") {
diff --git a/device/bluetooth/public/interfaces/test/fake_bluetooth.mojom b/device/bluetooth/public/interfaces/test/fake_bluetooth.mojom
index 826df33b..a9d71fa 100644
--- a/device/bluetooth/public/interfaces/test/fake_bluetooth.mojom
+++ b/device/bluetooth/public/interfaces/test/fake_bluetooth.mojom
@@ -4,6 +4,8 @@
 
 module bluetooth.mojom;
 
+import "device/bluetooth/public/interfaces/uuid.mojom";
+
 // FakeBluetooth and its related interfaces allow clients to control the global
 // Bluetooth State as well as simulate Bluetooth events including finding new
 // devices, simulating GATT attributes and its descendants, and simulating
@@ -38,4 +40,15 @@
 // See Bluetooth 4.2 Vol 3 Part C 2.2.2 "Roles when Operating over an
 // LE Physical Transport".
 interface FakeCentral {
+  // Simulates a peripheral with |address|, |name| and |known_service_uuids|
+  // that has already been connected to the system. If the peripheral existed
+  // already it updates its name and known UUIDs.
+  //
+  // Platforms offer methods to retrieve devices that have already been
+  // connected to the system or weren't connected through the UA e.g. a user
+  // connected a peripheral through the system's settings. This method is
+  // intended to simulate peripherals that those methods would return.
+  SimulatePreconnectedPeripheral(string address,
+                                 string name,
+                                 array<UUID> known_service_uuids) => ();
 };
diff --git a/device/bluetooth/test/fake_central.cc b/device/bluetooth/test/fake_central.cc
index 1236615f..8bc994f 100644
--- a/device/bluetooth/test/fake_central.cc
+++ b/device/bluetooth/test/fake_central.cc
@@ -8,8 +8,11 @@
 #include <string>
 #include <utility>
 
+#include "device/bluetooth/bluetooth_device.h"
 #include "device/bluetooth/bluetooth_discovery_filter.h"
+#include "device/bluetooth/bluetooth_uuid.h"
 #include "device/bluetooth/public/interfaces/test/fake_bluetooth.mojom.h"
+#include "device/bluetooth/test/fake_peripheral.h"
 
 namespace bluetooth {
 
@@ -17,7 +20,29 @@
                          mojom::FakeCentralRequest request)
     : state_(state), binding_(this, std::move(request)) {}
 
-FakeCentral::~FakeCentral() {}
+void FakeCentral::SimulatePreconnectedPeripheral(
+    const std::string& address,
+    const std::string& name,
+    const std::vector<device::BluetoothUUID>& known_service_uuids,
+    SimulatePreconnectedPeripheralCallback callback) {
+  auto device_iter = devices_.find(address);
+  if (device_iter == devices_.end()) {
+    auto fake_peripheral = base::MakeUnique<FakePeripheral>(this, address);
+
+    auto insert_iter = devices_.emplace(address, std::move(fake_peripheral));
+    DCHECK(insert_iter.second);
+    device_iter = insert_iter.first;
+  }
+
+  FakePeripheral* fake_peripheral =
+      static_cast<FakePeripheral*>(device_iter->second.get());
+  fake_peripheral->SetName(name);
+  fake_peripheral->SetGattConnected(true);
+  fake_peripheral->SetServiceUUIDs(device::BluetoothDevice::UUIDSet(
+      known_service_uuids.begin(), known_service_uuids.end()));
+
+  std::move(callback).Run();
+}
 
 std::string FakeCentral::GetAddress() const {
   NOTREACHED();
@@ -158,4 +183,6 @@
   NOTREACHED();
 }
 
+FakeCentral::~FakeCentral() {}
+
 }  // namespace bluetooth
diff --git a/device/bluetooth/test/fake_central.h b/device/bluetooth/test/fake_central.h
index c4e2be4..93fbd93 100644
--- a/device/bluetooth/test/fake_central.h
+++ b/device/bluetooth/test/fake_central.h
@@ -23,6 +23,13 @@
  public:
   FakeCentral(mojom::CentralState state, mojom::FakeCentralRequest request);
 
+  // FakeCentral overrides:
+  void SimulatePreconnectedPeripheral(
+      const std::string& address,
+      const std::string& name,
+      const std::vector<device::BluetoothUUID>& known_service_uuids,
+      SimulatePreconnectedPeripheralCallback callback) override;
+
   // BluetoothAdapter overrides:
   std::string GetAddress() const override;
   std::string GetName() const override;
diff --git a/device/bluetooth/test/fake_peripheral.cc b/device/bluetooth/test/fake_peripheral.cc
new file mode 100644
index 0000000..1515e99
--- /dev/null
+++ b/device/bluetooth/test/fake_peripheral.cc
@@ -0,0 +1,188 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "device/bluetooth/test/fake_peripheral.h"
+
+namespace bluetooth {
+
+FakePeripheral::FakePeripheral(FakeCentral* fake_central,
+                               const std::string& address)
+    : device::BluetoothDevice(fake_central),
+      address_(address),
+      gatt_connected_(false) {}
+
+FakePeripheral::~FakePeripheral() {}
+
+void FakePeripheral::SetName(base::Optional<std::string> name) {
+  name_ = std::move(name);
+}
+
+void FakePeripheral::SetGattConnected(bool connected) {
+  gatt_connected_ = connected;
+}
+
+void FakePeripheral::SetServiceUUIDs(UUIDSet service_uuids) {
+  service_uuids_ = std::move(service_uuids);
+}
+
+uint32_t FakePeripheral::GetBluetoothClass() const {
+  NOTREACHED();
+  return 0;
+}
+
+#if defined(OS_CHROMEOS) || defined(OS_LINUX)
+device::BluetoothTransport FakePeripheral::GetType() const {
+  NOTREACHED();
+  return device::BLUETOOTH_TRANSPORT_INVALID;
+}
+#endif
+
+std::string FakePeripheral::GetIdentifier() const {
+  NOTREACHED();
+  return std::string();
+}
+
+std::string FakePeripheral::GetAddress() const {
+  return address_;
+}
+
+device::BluetoothDevice::VendorIDSource FakePeripheral::GetVendorIDSource()
+    const {
+  NOTREACHED();
+  return VENDOR_ID_UNKNOWN;
+}
+
+uint16_t FakePeripheral::GetVendorID() const {
+  NOTREACHED();
+  return 0;
+}
+
+uint16_t FakePeripheral::GetProductID() const {
+  NOTREACHED();
+  return 0;
+}
+
+uint16_t FakePeripheral::GetDeviceID() const {
+  NOTREACHED();
+  return 0;
+}
+
+uint16_t FakePeripheral::GetAppearance() const {
+  NOTREACHED();
+  return 0;
+}
+
+base::Optional<std::string> FakePeripheral::GetName() const {
+  return name_;
+}
+
+base::string16 FakePeripheral::GetNameForDisplay() const {
+  return base::string16();
+}
+
+bool FakePeripheral::IsPaired() const {
+  NOTREACHED();
+  return false;
+}
+
+bool FakePeripheral::IsConnected() const {
+  NOTREACHED();
+  return false;
+}
+
+bool FakePeripheral::IsGattConnected() const {
+  return gatt_connected_;
+}
+
+bool FakePeripheral::IsConnectable() const {
+  NOTREACHED();
+  return false;
+}
+
+bool FakePeripheral::IsConnecting() const {
+  NOTREACHED();
+  return false;
+}
+
+device::BluetoothDevice::UUIDSet FakePeripheral::GetUUIDs() const {
+  return service_uuids_;
+}
+
+bool FakePeripheral::ExpectingPinCode() const {
+  NOTREACHED();
+  return false;
+}
+
+bool FakePeripheral::ExpectingPasskey() const {
+  NOTREACHED();
+  return false;
+}
+
+bool FakePeripheral::ExpectingConfirmation() const {
+  NOTREACHED();
+  return false;
+}
+
+void FakePeripheral::GetConnectionInfo(const ConnectionInfoCallback& callback) {
+  NOTREACHED();
+}
+
+void FakePeripheral::Connect(PairingDelegate* pairing_delegate,
+                             const base::Closure& callback,
+                             const ConnectErrorCallback& error_callback) {
+  NOTREACHED();
+}
+
+void FakePeripheral::SetPinCode(const std::string& pincode) {
+  NOTREACHED();
+}
+
+void FakePeripheral::SetPasskey(uint32_t passkey) {
+  NOTREACHED();
+}
+
+void FakePeripheral::ConfirmPairing() {
+  NOTREACHED();
+}
+
+void FakePeripheral::RejectPairing() {
+  NOTREACHED();
+}
+
+void FakePeripheral::CancelPairing() {
+  NOTREACHED();
+}
+
+void FakePeripheral::Disconnect(const base::Closure& callback,
+                                const ErrorCallback& error_callback) {
+  NOTREACHED();
+}
+
+void FakePeripheral::Forget(const base::Closure& callback,
+                            const ErrorCallback& error_callback) {
+  NOTREACHED();
+}
+
+void FakePeripheral::ConnectToService(
+    const device::BluetoothUUID& uuid,
+    const ConnectToServiceCallback& callback,
+    const ConnectToServiceErrorCallback& error_callback) {
+  NOTREACHED();
+}
+
+void FakePeripheral::ConnectToServiceInsecurely(
+    const device::BluetoothUUID& uuid,
+    const ConnectToServiceCallback& callback,
+    const ConnectToServiceErrorCallback& error_callback) {
+  NOTREACHED();
+}
+
+void FakePeripheral::CreateGattConnectionImpl() {
+  NOTREACHED();
+}
+
+void FakePeripheral::DisconnectGatt() {
+  NOTREACHED();
+}
+}  // namespace bluetooth
diff --git a/device/bluetooth/test/fake_peripheral.h b/device/bluetooth/test/fake_peripheral.h
new file mode 100644
index 0000000..56c17b2
--- /dev/null
+++ b/device/bluetooth/test/fake_peripheral.h
@@ -0,0 +1,94 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+#ifndef DEVICE_BLUETOOTH_TEST_FAKE_PERIPHERAL_H_
+#define DEVICE_BLUETOOTH_TEST_FAKE_PERIPHERAL_H_
+
+#include <string>
+
+#include "base/compiler_specific.h"
+#include "base/macros.h"
+#include "base/optional.h"
+#include "device/bluetooth/bluetooth_device.h"
+#include "device/bluetooth/test/fake_central.h"
+
+namespace bluetooth {
+
+// Implements device::BluetoothDevice. Meant to be used by FakeCentral
+// to keep track of the peripheral's state and attributes.
+class FakePeripheral : public device::BluetoothDevice {
+ public:
+  FakePeripheral(FakeCentral* fake_central, const std::string& address);
+  ~FakePeripheral() override;
+
+  // Changes the name of the device.
+  void SetName(base::Optional<std::string> name);
+
+  // Set it to indicate if the Peripheral is connected or not.
+  void SetGattConnected(bool gatt_connected);
+
+  // Updates the peripheral's UUIDs that are returned by
+  // BluetoothDevice::GetUUIDs().
+  void SetServiceUUIDs(UUIDSet service_uuids);
+
+  // BluetoothDevice overrides:
+  uint32_t GetBluetoothClass() const override;
+#if defined(OS_CHROMEOS) || defined(OS_LINUX)
+  device::BluetoothTransport GetType() const override;
+#endif
+  std::string GetIdentifier() const override;
+  std::string GetAddress() const override;
+  VendorIDSource GetVendorIDSource() const override;
+  uint16_t GetVendorID() const override;
+  uint16_t GetProductID() const override;
+  uint16_t GetDeviceID() const override;
+  uint16_t GetAppearance() const override;
+  base::Optional<std::string> GetName() const override;
+  base::string16 GetNameForDisplay() const override;
+  bool IsPaired() const override;
+  bool IsConnected() const override;
+  bool IsGattConnected() const override;
+  bool IsConnectable() const override;
+  bool IsConnecting() const override;
+  UUIDSet GetUUIDs() const override;
+  bool ExpectingPinCode() const override;
+  bool ExpectingPasskey() const override;
+  bool ExpectingConfirmation() const override;
+  void GetConnectionInfo(const ConnectionInfoCallback& callback) override;
+  void Connect(PairingDelegate* pairing_delegate,
+               const base::Closure& callback,
+               const ConnectErrorCallback& error_callback) override;
+  void SetPinCode(const std::string& pincode) override;
+  void SetPasskey(uint32_t passkey) override;
+  void ConfirmPairing() override;
+  void RejectPairing() override;
+  void CancelPairing() override;
+  void Disconnect(const base::Closure& callback,
+                  const ErrorCallback& error_callback) override;
+  void Forget(const base::Closure& callback,
+              const ErrorCallback& error_callback) override;
+  void ConnectToService(
+      const device::BluetoothUUID& uuid,
+      const ConnectToServiceCallback& callback,
+      const ConnectToServiceErrorCallback& error_callback) override;
+  void ConnectToServiceInsecurely(
+      const device::BluetoothUUID& uuid,
+      const ConnectToServiceCallback& callback,
+      const ConnectToServiceErrorCallback& error_callback) override;
+
+ protected:
+  void CreateGattConnectionImpl() override;
+  void DisconnectGatt() override;
+
+ private:
+  const std::string address_;
+  base::Optional<std::string> name_;
+  bool gatt_connected_;
+  UUIDSet service_uuids_;
+
+  DISALLOW_COPY_AND_ASSIGN(FakePeripheral);
+};
+
+}  // namespace bluetooth
+
+#endif  // DEVICE_BLUETOOTH_TEST_FAKE_PERIPHERAL_H_
diff --git a/gpu/BUILD.gn b/gpu/BUILD.gn
index 836c202..28791ce 100644
--- a/gpu/BUILD.gn
+++ b/gpu/BUILD.gn
@@ -289,6 +289,7 @@
     "command_buffer/service/program_manager_unittest.cc",
     "command_buffer/service/query_manager_unittest.cc",
     "command_buffer/service/renderbuffer_manager_unittest.cc",
+    "command_buffer/service/scheduler_unittest.cc",
     "command_buffer/service/shader_manager_unittest.cc",
     "command_buffer/service/shader_translator_cache_unittest.cc",
     "command_buffer/service/shader_translator_unittest.cc",
diff --git a/gpu/command_buffer/common/BUILD.gn b/gpu/command_buffer/common/BUILD.gn
index 4b69e04e..633e791 100644
--- a/gpu/command_buffer/common/BUILD.gn
+++ b/gpu/command_buffer/common/BUILD.gn
@@ -53,6 +53,8 @@
     "mailbox.h",
     "mailbox_holder.cc",
     "mailbox_holder.h",
+    "scheduling_priority.cc",
+    "scheduling_priority.h",
     "sync_token.cc",
     "sync_token.h",
     "texture_in_use_response.h",
diff --git a/gpu/command_buffer/common/scheduling_priority.cc b/gpu/command_buffer/common/scheduling_priority.cc
new file mode 100644
index 0000000..62b6456
--- /dev/null
+++ b/gpu/command_buffer/common/scheduling_priority.cc
@@ -0,0 +1,28 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "gpu/command_buffer/common/scheduling_priority.h"
+
+#include "base/logging.h"
+
+namespace gpu {
+
+const char* SchedulingPriorityToString(SchedulingPriority priority) {
+  switch (priority) {
+    case SchedulingPriority::kHighest:
+      return "Highest";
+    case SchedulingPriority::kHigh:
+      return "High";
+    case SchedulingPriority::kNormal:
+      return "Normal";
+    case SchedulingPriority::kLow:
+      return "Low";
+    case SchedulingPriority::kLowest:
+      return "Lowest";
+  }
+  NOTREACHED();
+  return "";
+}
+
+}  // namespace gpu
diff --git a/gpu/command_buffer/common/scheduling_priority.h b/gpu/command_buffer/common/scheduling_priority.h
new file mode 100644
index 0000000..ca93809
--- /dev/null
+++ b/gpu/command_buffer/common/scheduling_priority.h
@@ -0,0 +1,32 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef GPU_COMMAND_BUFFER_COMMON_SCHEDULING_PRIORITY_H_
+#define GPU_COMMAND_BUFFER_COMMON_SCHEDULING_PRIORITY_H_
+
+#include "gpu/gpu_export.h"
+
+namespace gpu {
+
+enum class SchedulingPriority {
+  // The Highest and High priorities can be used by priveleged clients only.
+  // This priority should be used for UI contexts.
+  kHighest,
+  // This priority is used by the scheduler for prioritizing contexts which have
+  // outstanding sync token waits.
+  kHigh,
+  // The following priorities can be used on unprivileged clients.
+  // This priority should be used as the default priority for all contexts.
+  kNormal,
+  kLow,
+  // This priority should be used for worker contexts.
+  kLowest,
+  kLast = kLowest
+};
+
+GPU_EXPORT const char* SchedulingPriorityToString(SchedulingPriority priority);
+
+}  // namespace gpu
+
+#endif  // GPU_COMMAND_BUFFER_COMMON_SCHEDULING_PRIORITY_H_
diff --git a/gpu/command_buffer/service/BUILD.gn b/gpu/command_buffer/service/BUILD.gn
index bf045d8..2c752e1 100644
--- a/gpu/command_buffer/service/BUILD.gn
+++ b/gpu/command_buffer/service/BUILD.gn
@@ -122,6 +122,8 @@
     "renderbuffer_manager.h",
     "sampler_manager.cc",
     "sampler_manager.h",
+    "scheduler.cc",
+    "scheduler.h",
     "sequence_id.h",
     "service_utils.cc",
     "service_utils.h",
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.cc b/gpu/command_buffer/service/gles2_cmd_decoder.cc
index 14d7a49..287191c 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder.cc
@@ -16054,6 +16054,9 @@
   const uint64_t release_count = c.release_count();
   if (!fence_sync_release_callback_.is_null())
     fence_sync_release_callback_.Run(release_count);
+  // Exit inner command processing loop so that we check the scheduling state
+  // and yield if necessary as we may have unblocked a higher priority context.
+  ExitCommandProcessingEarly();
   return error::kNoError;
 }
 
diff --git a/gpu/command_buffer/service/gpu_preferences.h b/gpu/command_buffer/service/gpu_preferences.h
index b7db89f..8dd0ff1 100644
--- a/gpu/command_buffer/service/gpu_preferences.h
+++ b/gpu/command_buffer/service/gpu_preferences.h
@@ -44,6 +44,9 @@
   // Prioritizes the UI's command stream in the GPU process.
   bool ui_prioritize_in_gpu_process = false;
 
+  // Enable the GPU process scheduler.
+  bool enable_gpu_scheduler = false;
+
   // Disables hardware acceleration of video decode, where available.
   bool disable_accelerated_video_decode = false;
 
diff --git a/gpu/command_buffer/service/scheduler.cc b/gpu/command_buffer/service/scheduler.cc
new file mode 100644
index 0000000..b77287d
--- /dev/null
+++ b/gpu/command_buffer/service/scheduler.cc
@@ -0,0 +1,499 @@
+// Copyright (c) 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "gpu/command_buffer/service/scheduler.h"
+
+#include <algorithm>
+
+#include "base/callback.h"
+#include "base/memory/ptr_util.h"
+#include "base/stl_util.h"
+#include "base/trace_event/trace_event.h"
+#include "base/trace_event/trace_event_argument.h"
+#include "gpu/command_buffer/service/sync_point_manager.h"
+
+namespace gpu {
+
+class Scheduler::Sequence {
+ public:
+  Sequence(SequenceId sequence_id,
+           SchedulingPriority priority,
+           scoped_refptr<SyncPointOrderData> order_data);
+
+  ~Sequence();
+
+  SequenceId sequence_id() const { return sequence_id_; }
+
+  const SchedulingState& scheduling_state() const { return scheduling_state_; }
+
+  bool enabled() const { return enabled_; }
+
+  bool scheduled() const { return running_state_ == SCHEDULED; }
+
+  bool running() const { return running_state_ == RUNNING; }
+
+  // The sequence is runnable if its enabled and has tasks which are not blocked
+  // by wait fences.
+  bool IsRunnable() const;
+
+  bool NeedsRescheduling() const;
+
+  void UpdateSchedulingState();
+
+  // If this sequence runs before the other sequence.
+  bool RunsBefore(const Sequence* other) const;
+
+  void SetEnabled(bool enabled);
+
+  // Sets running state to SCHEDULED.
+  void SetScheduled();
+
+  // Called before running the next task on the sequence. Returns the closure
+  // for the task. Sets running state to RUNNING.
+  base::OnceClosure BeginTask();
+
+  // Called after running the closure returned by BeginTask. Sets running state
+  // to IDLE.
+  void FinishTask();
+
+  // Enqueues a task in the sequence and returns the generated order number.
+  uint32_t ScheduleTask(base::OnceClosure closure);
+
+  // Continue running the current task with the given closure. Must be called in
+  // between |BeginTask| and |FinishTask|.
+  void ContinueTask(base::OnceClosure closure);
+
+  // Add a sync token fence that this sequence should wait on.
+  void AddWaitFence(const SyncToken& sync_token, uint32_t order_num);
+
+  // Remove a waiting sync token fence.
+  void RemoveWaitFence(const SyncToken& sync_token, uint32_t order_num);
+
+  // Add a sync token fence that this sequence is expected to release.
+  void AddReleaseFence(const SyncToken& sync_token, uint32_t order_num);
+
+  // Remove a release sync token fence.
+  void RemoveReleaseFence(const SyncToken& sync_token, uint32_t order_num);
+
+ private:
+  enum RunningState { IDLE, SCHEDULED, RUNNING };
+
+  struct Fence {
+    SyncToken sync_token;
+    uint32_t order_num;
+
+    bool operator==(const Fence& other) const {
+      return std::tie(sync_token, order_num) ==
+             std::tie(other.sync_token, other.order_num);
+    }
+  };
+
+  struct Task {
+    base::OnceClosure closure;
+    uint32_t order_num;
+  };
+
+  SchedulingPriority GetSchedulingPriority() const;
+
+  // If the sequence is enabled. Sequences are disabled/enabled based on when
+  // the command buffer is descheduled/scheduled.
+  bool enabled_ = true;
+
+  RunningState running_state_ = IDLE;
+
+  // Cached scheduling state used for comparison with other sequences using
+  // |RunsBefore|. Updated in |UpdateSchedulingState|.
+  SchedulingState scheduling_state_;
+
+  const SequenceId sequence_id_;
+
+  const SchedulingPriority priority_;
+
+  scoped_refptr<SyncPointOrderData> order_data_;
+
+  // Deque of tasks. Tasks are inserted at the back with increasing order number
+  // generated from SyncPointOrderData. If a running task needs to be continued,
+  // it is inserted at the front with the same order number.
+  std::deque<Task> tasks_;
+
+  // List of fences that this sequence is waiting on. Fences are inserted in
+  // increasing order number but may be removed out of order. Tasks are blocked
+  // if there's a wait fence with order number less than or equal to the task's
+  // order number.
+  std::vector<Fence> wait_fences_;
+
+  // List of fences that this sequence is expected to release. If this list is
+  // non-empty, the priority of the sequence is raised.
+  std::vector<Fence> release_fences_;
+
+  DISALLOW_COPY_AND_ASSIGN(Sequence);
+};
+
+Scheduler::SchedulingState::SchedulingState() = default;
+Scheduler::SchedulingState::SchedulingState(const SchedulingState& other) =
+    default;
+Scheduler::SchedulingState::~SchedulingState() = default;
+
+std::unique_ptr<base::trace_event::ConvertableToTraceFormat>
+Scheduler::SchedulingState::AsValue() const {
+  std::unique_ptr<base::trace_event::TracedValue> state(
+      new base::trace_event::TracedValue());
+  state->SetInteger("sequence_id", sequence_id.GetUnsafeValue());
+  state->SetString("priority", SchedulingPriorityToString(priority));
+  state->SetInteger("order_num", order_num);
+  return std::move(state);
+}
+
+Scheduler::Sequence::Sequence(SequenceId sequence_id,
+                              SchedulingPriority priority,
+                              scoped_refptr<SyncPointOrderData> order_data)
+    : sequence_id_(sequence_id),
+      priority_(priority),
+      order_data_(std::move(order_data)) {}
+
+Scheduler::Sequence::~Sequence() {
+  order_data_->Destroy();
+}
+
+bool Scheduler::Sequence::NeedsRescheduling() const {
+  return running_state_ != IDLE &&
+         scheduling_state_.priority != GetSchedulingPriority();
+}
+
+bool Scheduler::Sequence::IsRunnable() const {
+  return enabled_ && !tasks_.empty() &&
+         (wait_fences_.empty() ||
+          wait_fences_.front().order_num > tasks_.front().order_num);
+}
+
+SchedulingPriority Scheduler::Sequence::GetSchedulingPriority() const {
+  if (!release_fences_.empty())
+    return std::min(priority_, SchedulingPriority::kHigh);
+  return priority_;
+}
+
+bool Scheduler::Sequence::RunsBefore(const Scheduler::Sequence* other) const {
+  return scheduling_state_.RunsBefore(other->scheduling_state());
+}
+
+void Scheduler::Sequence::SetEnabled(bool enabled) {
+  if (enabled_ == enabled)
+    return;
+  DCHECK_EQ(running_state_, enabled ? IDLE : RUNNING);
+  enabled_ = enabled;
+}
+
+void Scheduler::Sequence::SetScheduled() {
+  DCHECK_NE(running_state_, RUNNING);
+  running_state_ = SCHEDULED;
+  UpdateSchedulingState();
+}
+
+void Scheduler::Sequence::UpdateSchedulingState() {
+  scheduling_state_.sequence_id = sequence_id_;
+  scheduling_state_.priority = GetSchedulingPriority();
+
+  uint32_t order_num = UINT32_MAX;  // IDLE
+  if (running_state_ == SCHEDULED) {
+    DCHECK(!tasks_.empty());
+    order_num = tasks_.front().order_num;
+  } else if (running_state_ == RUNNING) {
+    order_num = order_data_->current_order_num();
+  }
+  scheduling_state_.order_num = order_num;
+}
+
+void Scheduler::Sequence::ContinueTask(base::OnceClosure closure) {
+  DCHECK_EQ(running_state_, RUNNING);
+  tasks_.push_front({std::move(closure), order_data_->current_order_num()});
+}
+
+uint32_t Scheduler::Sequence::ScheduleTask(base::OnceClosure closure) {
+  uint32_t order_num = order_data_->GenerateUnprocessedOrderNumber();
+  tasks_.push_back({std::move(closure), order_num});
+  return order_num;
+}
+
+base::OnceClosure Scheduler::Sequence::BeginTask() {
+  DCHECK(!tasks_.empty());
+
+  DCHECK_EQ(running_state_, SCHEDULED);
+  running_state_ = RUNNING;
+
+  base::OnceClosure closure = std::move(tasks_.front().closure);
+  uint32_t order_num = tasks_.front().order_num;
+  tasks_.pop_front();
+
+  order_data_->BeginProcessingOrderNumber(order_num);
+
+  UpdateSchedulingState();
+
+  return closure;
+}
+
+void Scheduler::Sequence::FinishTask() {
+  DCHECK_EQ(running_state_, RUNNING);
+  running_state_ = IDLE;
+  uint32_t order_num = order_data_->current_order_num();
+  if (!tasks_.empty() && tasks_.front().order_num == order_num) {
+    order_data_->PauseProcessingOrderNumber(order_num);
+  } else {
+    order_data_->FinishProcessingOrderNumber(order_num);
+  }
+  UpdateSchedulingState();
+}
+
+void Scheduler::Sequence::AddWaitFence(const SyncToken& sync_token,
+                                       uint32_t order_num) {
+  wait_fences_.push_back({sync_token, order_num});
+}
+
+void Scheduler::Sequence::RemoveWaitFence(const SyncToken& sync_token,
+                                          uint32_t order_num) {
+  base::Erase(wait_fences_, Fence{sync_token, order_num});
+}
+
+void Scheduler::Sequence::AddReleaseFence(const SyncToken& sync_token,
+                                          uint32_t order_num) {
+  release_fences_.push_back({sync_token, order_num});
+}
+
+void Scheduler::Sequence::RemoveReleaseFence(const SyncToken& sync_token,
+                                             uint32_t order_num) {
+  base::Erase(release_fences_, Fence{sync_token, order_num});
+}
+
+Scheduler::Scheduler(scoped_refptr<base::SingleThreadTaskRunner> task_runner,
+                     SyncPointManager* sync_point_manager)
+    : task_runner_(std::move(task_runner)),
+      sync_point_manager_(sync_point_manager),
+      weak_factory_(this) {
+  DCHECK(thread_checker_.CalledOnValidThread());
+}
+
+Scheduler::~Scheduler() {
+  DCHECK(thread_checker_.CalledOnValidThread());
+}
+
+SequenceId Scheduler::CreateSequence(SchedulingPriority priority) {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  base::AutoLock auto_lock(lock_);
+  scoped_refptr<SyncPointOrderData> order_data =
+      sync_point_manager_->CreateSyncPointOrderData();
+  SequenceId sequence_id = order_data->sequence_id();
+  auto sequence =
+      base::MakeUnique<Sequence>(sequence_id, priority, std::move(order_data));
+  sequences_.emplace(sequence_id, std::move(sequence));
+  return sequence_id;
+}
+
+void Scheduler::DestroySequence(SequenceId sequence_id) {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  base::AutoLock auto_lock(lock_);
+
+  Sequence* sequence = GetSequence(sequence_id);
+  DCHECK(sequence);
+  if (sequence->scheduled())
+    rebuild_scheduling_queue_ = true;
+
+  sequences_.erase(sequence_id);
+}
+
+Scheduler::Sequence* Scheduler::GetSequence(SequenceId sequence_id) {
+  lock_.AssertAcquired();
+  auto it = sequences_.find(sequence_id);
+  if (it != sequences_.end())
+    return it->second.get();
+  return nullptr;
+}
+
+void Scheduler::EnableSequence(SequenceId sequence_id) {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  base::AutoLock auto_lock(lock_);
+  Sequence* sequence = GetSequence(sequence_id);
+  DCHECK(sequence);
+  sequence->SetEnabled(true);
+  TryScheduleSequence(sequence);
+}
+
+void Scheduler::DisableSequence(SequenceId sequence_id) {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  base::AutoLock auto_lock(lock_);
+  Sequence* sequence = GetSequence(sequence_id);
+  DCHECK(sequence);
+  sequence->SetEnabled(false);
+}
+
+void Scheduler::ScheduleTask(SequenceId sequence_id,
+                             base::OnceClosure closure,
+                             const std::vector<SyncToken>& sync_token_fences) {
+  base::AutoLock auto_lock(lock_);
+  Sequence* sequence = GetSequence(sequence_id);
+  DCHECK(sequence);
+
+  uint32_t order_num = sequence->ScheduleTask(std::move(closure));
+
+  for (const SyncToken& sync_token : sync_token_fences) {
+    SequenceId release_id =
+        sync_point_manager_->GetSyncTokenReleaseSequenceId(sync_token);
+    Sequence* release_sequence = GetSequence(release_id);
+    if (!release_sequence)
+      continue;
+    if (sync_point_manager_->Wait(
+            sync_token, order_num,
+            base::Bind(&Scheduler::SyncTokenFenceReleased,
+                       weak_factory_.GetWeakPtr(), sync_token, order_num,
+                       release_id, sequence_id))) {
+      sequence->AddWaitFence(sync_token, order_num);
+      release_sequence->AddReleaseFence(sync_token, order_num);
+      TryScheduleSequence(release_sequence);
+    }
+  }
+
+  TryScheduleSequence(sequence);
+}
+
+void Scheduler::ContinueTask(SequenceId sequence_id,
+                             base::OnceClosure closure) {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  base::AutoLock auto_lock(lock_);
+  Sequence* sequence = GetSequence(sequence_id);
+  DCHECK(sequence);
+  sequence->ContinueTask(std::move(closure));
+}
+
+bool Scheduler::ShouldYield(SequenceId sequence_id) {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  base::AutoLock auto_lock(lock_);
+
+  Sequence* sequence = GetSequence(sequence_id);
+  DCHECK(sequence);
+  DCHECK(sequence->running());
+
+  if (should_yield_)
+    return true;
+
+  RebuildSchedulingQueue();
+
+  sequence->UpdateSchedulingState();
+
+  if (!scheduling_queue_.empty()) {
+    Sequence* next_sequence =
+        GetSequence(scheduling_queue_.front().sequence_id);
+    DCHECK(next_sequence);
+    if (next_sequence->RunsBefore(sequence))
+      should_yield_ = true;
+  }
+
+  return should_yield_;
+}
+
+void Scheduler::SyncTokenFenceReleased(const SyncToken& sync_token,
+                                       uint32_t order_num,
+                                       SequenceId release_sequence_id,
+                                       SequenceId waiting_sequence_id) {
+  base::AutoLock auto_lock(lock_);
+  Sequence* sequence = GetSequence(waiting_sequence_id);
+  if (sequence) {
+    sequence->RemoveWaitFence(sync_token, order_num);
+    TryScheduleSequence(sequence);
+  }
+  Sequence* release_sequence = GetSequence(release_sequence_id);
+  if (release_sequence) {
+    release_sequence->RemoveReleaseFence(sync_token, order_num);
+    TryScheduleSequence(release_sequence);
+  }
+}
+
+void Scheduler::TryScheduleSequence(Sequence* sequence) {
+  lock_.AssertAcquired();
+
+  if (sequence->running())
+    return;
+
+  if (sequence->NeedsRescheduling()) {
+    DCHECK(sequence->IsRunnable());
+    rebuild_scheduling_queue_ = true;
+  } else if (!sequence->scheduled() && sequence->IsRunnable()) {
+    sequence->SetScheduled();
+    scheduling_queue_.push_back(sequence->scheduling_state());
+    std::push_heap(scheduling_queue_.begin(), scheduling_queue_.end(),
+                   &SchedulingState::Comparator);
+  }
+
+  if (!running_) {
+    TRACE_EVENT_ASYNC_BEGIN0("gpu", "Scheduler::Running", this);
+    running_ = true;
+    task_runner_->PostTask(FROM_HERE, base::Bind(&Scheduler::RunNextTask,
+                                                 weak_factory_.GetWeakPtr()));
+  }
+}
+
+void Scheduler::RebuildSchedulingQueue() {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  lock_.AssertAcquired();
+
+  if (!rebuild_scheduling_queue_)
+    return;
+  rebuild_scheduling_queue_ = false;
+
+  scheduling_queue_.clear();
+  for (const auto& kv : sequences_) {
+    Sequence* sequence = kv.second.get();
+    if (!sequence->IsRunnable() || sequence->running())
+      continue;
+    sequence->SetScheduled();
+    scheduling_queue_.push_back(sequence->scheduling_state());
+  }
+
+  std::make_heap(scheduling_queue_.begin(), scheduling_queue_.end(),
+                 &SchedulingState::Comparator);
+}
+
+void Scheduler::RunNextTask() {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  base::AutoLock auto_lock(lock_);
+
+  should_yield_ = false;
+
+  RebuildSchedulingQueue();
+
+  if (scheduling_queue_.empty()) {
+    TRACE_EVENT_ASYNC_END0("gpu", "Scheduler::Running", this);
+    running_ = false;
+    return;
+  }
+
+  std::pop_heap(scheduling_queue_.begin(), scheduling_queue_.end(),
+                &SchedulingState::Comparator);
+  SchedulingState state = scheduling_queue_.back();
+  scheduling_queue_.pop_back();
+
+  TRACE_EVENT1("gpu", "Scheduler::RunNextTask", "state", state.AsValue());
+
+  DCHECK(GetSequence(state.sequence_id));
+  base::OnceClosure closure = GetSequence(state.sequence_id)->BeginTask();
+
+  {
+    base::AutoUnlock auto_unlock(lock_);
+    std::move(closure).Run();
+  }
+
+  // Check if sequence hasn't been destroyed.
+  Sequence* sequence = GetSequence(state.sequence_id);
+  if (sequence) {
+    sequence->FinishTask();
+    if (sequence->IsRunnable()) {
+      sequence->SetScheduled();
+      scheduling_queue_.push_back(sequence->scheduling_state());
+      std::push_heap(scheduling_queue_.begin(), scheduling_queue_.end(),
+                     &SchedulingState::Comparator);
+    }
+  }
+
+  task_runner_->PostTask(FROM_HERE, base::Bind(&Scheduler::RunNextTask,
+                                               weak_factory_.GetWeakPtr()));
+}
+
+}  // namespace gpu
diff --git a/gpu/command_buffer/service/scheduler.h b/gpu/command_buffer/service/scheduler.h
new file mode 100644
index 0000000..c6dab1cf
--- /dev/null
+++ b/gpu/command_buffer/service/scheduler.h
@@ -0,0 +1,138 @@
+// Copyright (c) 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef GPU_COMMAND_BUFFER_SERVICE_SCHEDULER_H_
+#define GPU_COMMAND_BUFFER_SERVICE_SCHEDULER_H_
+
+#include <queue>
+#include <vector>
+
+#include "base/callback.h"
+#include "base/containers/flat_map.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/weak_ptr.h"
+#include "base/synchronization/lock.h"
+#include "base/threading/thread_checker.h"
+#include "gpu/command_buffer/common/scheduling_priority.h"
+#include "gpu/command_buffer/common/sync_token.h"
+#include "gpu/command_buffer/service/sequence_id.h"
+#include "gpu/gpu_export.h"
+
+namespace base {
+class SingleThreadTaskRunner;
+namespace trace_event {
+class ConvertableToTraceFormat;
+}
+}
+
+namespace gpu {
+class SyncPointManager;
+
+class GPU_EXPORT Scheduler {
+ public:
+  Scheduler(scoped_refptr<base::SingleThreadTaskRunner> task_runner,
+            SyncPointManager* sync_point_manager);
+
+  virtual ~Scheduler();
+
+  // Create a sequence with given priority. Returns an identifier for the
+  // sequence that can be used with SyncPonintManager for creating sync point
+  // release clients. Sequences start off as enabled (see |EnableSequence|).
+  SequenceId CreateSequence(SchedulingPriority priority);
+
+  // Destroy the sequence and run any scheduled tasks immediately.
+  void DestroySequence(SequenceId sequence_id);
+
+  // Enables the sequence so that its tasks may be scheduled.
+  void EnableSequence(SequenceId sequence_id);
+
+  // Disables the sequence.
+  void DisableSequence(SequenceId sequence_id);
+
+  // Schedules task (closure) to run on the sequence. The task is blocked until
+  // the sync token fences are released or determined to be invalid. Tasks are
+  // run in the order in which they are submitted.
+  void ScheduleTask(SequenceId sequence_id,
+                    base::OnceClosure closure,
+                    const std::vector<SyncToken>& sync_token_fences);
+
+  // Continue running task on the sequence with the closure. This must be called
+  // while running a previously scheduled task.
+  void ContinueTask(SequenceId sequence_id, base::OnceClosure closure);
+
+  // If the sequence should yield so that a higher priority sequence may run.
+  bool ShouldYield(SequenceId sequence_id);
+
+ private:
+  class Sequence;
+
+  struct SchedulingState {
+    static bool Comparator(const SchedulingState& lhs,
+                           const SchedulingState& rhs) {
+      return rhs.RunsBefore(lhs);
+    }
+
+    SchedulingState();
+    SchedulingState(const SchedulingState& other);
+    ~SchedulingState();
+
+    bool RunsBefore(const SchedulingState& other) const {
+      return std::tie(priority, order_num) <
+             std::tie(other.priority, other.order_num);
+    }
+
+    std::unique_ptr<base::trace_event::ConvertableToTraceFormat> AsValue()
+        const;
+
+    SequenceId sequence_id;
+    SchedulingPriority priority = SchedulingPriority::kLowest;
+    uint32_t order_num = 0;
+  };
+
+  void SyncTokenFenceReleased(const SyncToken& sync_token,
+                              uint32_t order_num,
+                              SequenceId release_sequence_id,
+                              SequenceId waiting_sequence_id);
+
+  void TryScheduleSequence(Sequence* sequence);
+
+  void RebuildSchedulingQueue();
+
+  Sequence* GetSequence(SequenceId sequence_id);
+
+  void RunNextTask();
+
+  scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
+
+  SyncPointManager* const sync_point_manager_;
+
+  mutable base::Lock lock_;
+
+  // The following are protected by |lock_|.
+  bool running_ = false;
+
+  base::flat_map<SequenceId, std::unique_ptr<Sequence>> sequences_;
+
+  // Used as a priority queue for scheduling sequences. Min heap of
+  // SchedulingState with highest priority (lowest order) in front.
+  std::vector<SchedulingState> scheduling_queue_;
+
+  // If the running sequence should yield so that a higher priority sequence can
+  // run.
+  bool should_yield_ = false;
+
+  // If the scheduling queue needs to be rebuild because a sequence changed
+  // priority.
+  bool rebuild_scheduling_queue_ = false;
+
+  base::ThreadChecker thread_checker_;
+
+  base::WeakPtrFactory<Scheduler> weak_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(Scheduler);
+};
+
+}  // namespace gpu
+
+#endif  // GPU_COMMAND_BUFFER_SERVICE_SCHEDULER_H_
diff --git a/gpu/command_buffer/service/scheduler_unittest.cc b/gpu/command_buffer/service/scheduler_unittest.cc
new file mode 100644
index 0000000..43328b3
--- /dev/null
+++ b/gpu/command_buffer/service/scheduler_unittest.cc
@@ -0,0 +1,335 @@
+// Copyright (c) 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "gpu/command_buffer/service/scheduler.h"
+
+#include <algorithm>
+
+#include "base/bind.h"
+#include "base/memory/ptr_util.h"
+#include "base/test/test_simple_task_runner.h"
+#include "gpu/command_buffer/service/sync_point_manager.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace gpu {
+namespace {
+
+template <typename T>
+void RunFunctor(T functor) {
+  functor();
+}
+
+template <typename T>
+base::OnceClosure GetClosure(T functor) {
+  return base::BindOnce(&RunFunctor<T>, functor);
+}
+
+class SchedulerTest : public testing::Test {
+ public:
+  SchedulerTest()
+      : task_runner_(new base::TestSimpleTaskRunner()),
+        sync_point_manager_(new SyncPointManager),
+        scheduler_(new Scheduler(task_runner_, sync_point_manager_.get())) {}
+
+ protected:
+  base::TestSimpleTaskRunner* task_runner() const { return task_runner_.get(); }
+
+  SyncPointManager* sync_point_manager() const {
+    return sync_point_manager_.get();
+  }
+
+  Scheduler* scheduler() const { return scheduler_.get(); }
+
+ private:
+  scoped_refptr<base::TestSimpleTaskRunner> task_runner_;
+  std::unique_ptr<SyncPointManager> sync_point_manager_;
+  std::unique_ptr<Scheduler> scheduler_;
+};
+
+TEST_F(SchedulerTest, ScheduledTasksRunInOrder) {
+  SequenceId sequence_id =
+      scheduler()->CreateSequence(SchedulingPriority::kNormal);
+
+  bool ran1 = false;
+  scheduler()->ScheduleTask(sequence_id, GetClosure([&] { ran1 = true; }),
+                            std::vector<SyncToken>());
+
+  bool ran2 = false;
+  scheduler()->ScheduleTask(sequence_id, GetClosure([&] { ran2 = true; }),
+                            std::vector<SyncToken>());
+
+  task_runner()->RunPendingTasks();
+  EXPECT_TRUE(ran1);
+
+  task_runner()->RunPendingTasks();
+  EXPECT_TRUE(ran2);
+}
+
+TEST_F(SchedulerTest, ContinuedTasksRunFirst) {
+  SequenceId sequence_id =
+      scheduler()->CreateSequence(SchedulingPriority::kNormal);
+
+  bool ran1 = false;
+  bool continued1 = false;
+  scheduler()->ScheduleTask(sequence_id, GetClosure([&] {
+                              scheduler()->ContinueTask(
+                                  sequence_id,
+                                  GetClosure([&] { continued1 = true; }));
+                              ran1 = true;
+                            }),
+                            std::vector<SyncToken>());
+
+  bool ran2 = false;
+  scheduler()->ScheduleTask(sequence_id, GetClosure([&] { ran2 = true; }),
+                            std::vector<SyncToken>());
+
+  task_runner()->RunPendingTasks();
+  EXPECT_TRUE(ran1);
+  EXPECT_FALSE(continued1);
+  EXPECT_FALSE(ran2);
+
+  task_runner()->RunPendingTasks();
+  EXPECT_TRUE(continued1);
+  EXPECT_FALSE(ran2);
+
+  task_runner()->RunPendingTasks();
+  EXPECT_TRUE(ran2);
+}
+
+TEST_F(SchedulerTest, SequencesRunInPriorityOrder) {
+  SequenceId sequence_id1 =
+      scheduler()->CreateSequence(SchedulingPriority::kLowest);
+  bool ran1 = false;
+  scheduler()->ScheduleTask(sequence_id1, GetClosure([&] { ran1 = true; }),
+                            std::vector<SyncToken>());
+
+  SequenceId sequence_id2 =
+      scheduler()->CreateSequence(SchedulingPriority::kNormal);
+  bool ran2 = false;
+  scheduler()->ScheduleTask(sequence_id2, GetClosure([&] { ran2 = true; }),
+                            std::vector<SyncToken>());
+
+  SequenceId sequence_id3 =
+      scheduler()->CreateSequence(SchedulingPriority::kHighest);
+  bool ran3 = false;
+  scheduler()->ScheduleTask(sequence_id3, GetClosure([&] { ran3 = true; }),
+                            std::vector<SyncToken>());
+
+  task_runner()->RunPendingTasks();
+  EXPECT_TRUE(ran3);
+
+  task_runner()->RunPendingTasks();
+  EXPECT_TRUE(ran2);
+
+  task_runner()->RunPendingTasks();
+  EXPECT_TRUE(ran1);
+}
+
+TEST_F(SchedulerTest, SequencesOfSamePriorityRunInOrder) {
+  SequenceId sequence_id1 =
+      scheduler()->CreateSequence(SchedulingPriority::kNormal);
+  bool ran1 = false;
+  scheduler()->ScheduleTask(sequence_id1, GetClosure([&] { ran1 = true; }),
+                            std::vector<SyncToken>());
+
+  SequenceId sequence_id2 =
+      scheduler()->CreateSequence(SchedulingPriority::kNormal);
+  bool ran2 = false;
+  scheduler()->ScheduleTask(sequence_id2, GetClosure([&] { ran2 = true; }),
+                            std::vector<SyncToken>());
+
+  SequenceId sequence_id3 =
+      scheduler()->CreateSequence(SchedulingPriority::kNormal);
+  bool ran3 = false;
+  scheduler()->ScheduleTask(sequence_id3, GetClosure([&] { ran3 = true; }),
+                            std::vector<SyncToken>());
+
+  SequenceId sequence_id4 =
+      scheduler()->CreateSequence(SchedulingPriority::kNormal);
+  bool ran4 = false;
+  scheduler()->ScheduleTask(sequence_id4, GetClosure([&] { ran4 = true; }),
+                            std::vector<SyncToken>());
+
+  task_runner()->RunPendingTasks();
+  EXPECT_TRUE(ran1);
+
+  task_runner()->RunPendingTasks();
+  EXPECT_TRUE(ran2);
+
+  task_runner()->RunPendingTasks();
+  EXPECT_TRUE(ran3);
+
+  task_runner()->RunPendingTasks();
+  EXPECT_TRUE(ran4);
+}
+
+TEST_F(SchedulerTest, SequenceWaitsForFence) {
+  SequenceId sequence_id1 =
+      scheduler()->CreateSequence(SchedulingPriority::kHighest);
+  SequenceId sequence_id2 =
+      scheduler()->CreateSequence(SchedulingPriority::kNormal);
+
+  CommandBufferNamespace namespace_id = CommandBufferNamespace::GPU_IO;
+  CommandBufferId command_buffer_id = CommandBufferId::FromUnsafeValue(1);
+
+  scoped_refptr<SyncPointClientState> release_state =
+      sync_point_manager()->CreateSyncPointClientState(
+          namespace_id, command_buffer_id, sequence_id2);
+
+  uint64_t release = 1;
+  bool ran2 = false;
+  scheduler()->ScheduleTask(sequence_id2, GetClosure([&] {
+                              release_state->ReleaseFenceSync(release);
+                              ran2 = true;
+                            }),
+                            std::vector<SyncToken>());
+
+  SyncToken sync_token(namespace_id, 0 /* extra_data_field */,
+                       command_buffer_id, release);
+
+  bool ran1 = false;
+  scheduler()->ScheduleTask(sequence_id1, GetClosure([&] { ran1 = true; }),
+                            {sync_token});
+
+  task_runner()->RunPendingTasks();
+  EXPECT_FALSE(ran1);
+  EXPECT_TRUE(ran2);
+  EXPECT_TRUE(sync_point_manager()->IsSyncTokenReleased(sync_token));
+
+  task_runner()->RunPendingTasks();
+  EXPECT_TRUE(ran1);
+
+  release_state->Destroy();
+}
+
+TEST_F(SchedulerTest, SequenceDoesNotWaitForInvalidFence) {
+  SequenceId sequence_id1 =
+      scheduler()->CreateSequence(SchedulingPriority::kNormal);
+
+  SequenceId sequence_id2 =
+      scheduler()->CreateSequence(SchedulingPriority::kNormal);
+  CommandBufferNamespace namespace_id = CommandBufferNamespace::GPU_IO;
+  CommandBufferId command_buffer_id = CommandBufferId::FromUnsafeValue(1);
+  scoped_refptr<SyncPointClientState> release_state =
+      sync_point_manager()->CreateSyncPointClientState(
+          namespace_id, command_buffer_id, sequence_id2);
+
+  uint64_t release = 1;
+  SyncToken sync_token(namespace_id, 0 /* extra_data_field */,
+                       command_buffer_id, release);
+
+  bool ran1 = false;
+  scheduler()->ScheduleTask(sequence_id1, GetClosure([&] { ran1 = true; }),
+                            {sync_token});
+
+  // Release task is scheduled after wait task so release is treated as non-
+  // existent.
+  bool ran2 = false;
+  scheduler()->ScheduleTask(sequence_id2, GetClosure([&] {
+                              release_state->ReleaseFenceSync(release);
+                              ran2 = true;
+                            }),
+                            std::vector<SyncToken>());
+
+  task_runner()->RunPendingTasks();
+  EXPECT_TRUE(ran1);
+  EXPECT_FALSE(ran2);
+  EXPECT_FALSE(sync_point_manager()->IsSyncTokenReleased(sync_token));
+
+  task_runner()->RunPendingTasks();
+  EXPECT_TRUE(ran2);
+  EXPECT_TRUE(sync_point_manager()->IsSyncTokenReleased(sync_token));
+
+  release_state->Destroy();
+}
+
+TEST_F(SchedulerTest, ReleaseSequenceIsPrioritized) {
+  SequenceId sequence_id1 =
+      scheduler()->CreateSequence(SchedulingPriority::kNormal);
+
+  bool ran1 = false;
+  scheduler()->ScheduleTask(sequence_id1, GetClosure([&] { ran1 = true; }),
+                            std::vector<SyncToken>());
+
+  SequenceId sequence_id2 =
+      scheduler()->CreateSequence(SchedulingPriority::kLowest);
+  CommandBufferNamespace namespace_id = CommandBufferNamespace::GPU_IO;
+  CommandBufferId command_buffer_id = CommandBufferId::FromUnsafeValue(1);
+  scoped_refptr<SyncPointClientState> release_state =
+      sync_point_manager()->CreateSyncPointClientState(
+          namespace_id, command_buffer_id, sequence_id2);
+
+  uint64_t release = 1;
+  bool ran2 = false;
+  scheduler()->ScheduleTask(sequence_id2, GetClosure([&] {
+                              release_state->ReleaseFenceSync(release);
+                              ran2 = true;
+                            }),
+                            std::vector<SyncToken>());
+
+  bool ran3 = false;
+  SyncToken sync_token(namespace_id, 0 /* extra_data_field */,
+                       command_buffer_id, release);
+  SequenceId sequence_id3 =
+      scheduler()->CreateSequence(SchedulingPriority::kHighest);
+  scheduler()->ScheduleTask(sequence_id3, GetClosure([&] { ran3 = true; }),
+                            {sync_token});
+
+  task_runner()->RunPendingTasks();
+  EXPECT_FALSE(ran1);
+  EXPECT_TRUE(ran2);
+  EXPECT_FALSE(ran3);
+  EXPECT_TRUE(sync_point_manager()->IsSyncTokenReleased(sync_token));
+
+  task_runner()->RunPendingTasks();
+  EXPECT_FALSE(ran1);
+  EXPECT_TRUE(ran3);
+
+  task_runner()->RunPendingTasks();
+  EXPECT_TRUE(ran1);
+
+  release_state->Destroy();
+}
+
+TEST_F(SchedulerTest, ReleaseSequenceShouldYield) {
+  SequenceId sequence_id1 =
+      scheduler()->CreateSequence(SchedulingPriority::kLowest);
+  CommandBufferNamespace namespace_id = CommandBufferNamespace::GPU_IO;
+  CommandBufferId command_buffer_id = CommandBufferId::FromUnsafeValue(1);
+  scoped_refptr<SyncPointClientState> release_state =
+      sync_point_manager()->CreateSyncPointClientState(
+          namespace_id, command_buffer_id, sequence_id1);
+
+  uint64_t release = 1;
+  bool ran1 = false;
+  scheduler()->ScheduleTask(
+      sequence_id1, GetClosure([&] {
+        EXPECT_FALSE(scheduler()->ShouldYield(sequence_id1));
+        release_state->ReleaseFenceSync(release);
+        EXPECT_TRUE(scheduler()->ShouldYield(sequence_id1));
+        ran1 = true;
+      }),
+      std::vector<SyncToken>());
+
+  bool ran2 = false;
+  SyncToken sync_token(namespace_id, 0 /* extra_data_field */,
+                       command_buffer_id, release);
+  SequenceId sequence_id2 =
+      scheduler()->CreateSequence(SchedulingPriority::kHighest);
+  scheduler()->ScheduleTask(sequence_id2, GetClosure([&] { ran2 = true; }),
+                            {sync_token});
+
+  task_runner()->RunPendingTasks();
+  EXPECT_TRUE(ran1);
+  EXPECT_FALSE(ran2);
+  EXPECT_TRUE(sync_point_manager()->IsSyncTokenReleased(sync_token));
+
+  task_runner()->RunPendingTasks();
+  EXPECT_TRUE(ran2);
+
+  release_state->Destroy();
+}
+
+}  // namespace
+}  // namespace gpu
diff --git a/gpu/ipc/client/command_buffer_proxy_impl.cc b/gpu/ipc/client/command_buffer_proxy_impl.cc
index a7c73080..61aa361 100644
--- a/gpu/ipc/client/command_buffer_proxy_impl.cc
+++ b/gpu/ipc/client/command_buffer_proxy_impl.cc
@@ -60,7 +60,6 @@
       stream_id_(stream_id),
       weak_this_(AsWeakPtr()) {
   DCHECK(route_id);
-  DCHECK_NE(stream_id, GPU_STREAM_INVALID);
 }
 
 // static
@@ -69,7 +68,7 @@
     gpu::SurfaceHandle surface_handle,
     CommandBufferProxyImpl* share_group,
     int32_t stream_id,
-    gpu::GpuStreamPriority stream_priority,
+    gpu::SchedulingPriority stream_priority,
     const gpu::gles2::ContextCreationAttribHelper& attribs,
     const GURL& active_url,
     scoped_refptr<base::SingleThreadTaskRunner> task_runner) {
@@ -672,9 +671,6 @@
 
   // If waiting on a different stream, flush pending commands on that stream.
   int32_t release_stream_id = sync_token.extra_data_field();
-  if (release_stream_id == gpu::GPU_STREAM_INVALID)
-    return false;
-
   if (release_stream_id != stream_id_)
     channel_->FlushPendingStream(release_stream_id);
 
diff --git a/gpu/ipc/client/command_buffer_proxy_impl.h b/gpu/ipc/client/command_buffer_proxy_impl.h
index a7b6f8e..b4b2922 100644
--- a/gpu/ipc/client/command_buffer_proxy_impl.h
+++ b/gpu/ipc/client/command_buffer_proxy_impl.h
@@ -27,8 +27,8 @@
 #include "gpu/command_buffer/common/command_buffer_id.h"
 #include "gpu/command_buffer/common/command_buffer_shared.h"
 #include "gpu/command_buffer/common/gpu_memory_allocation.h"
+#include "gpu/command_buffer/common/scheduling_priority.h"
 #include "gpu/gpu_export.h"
-#include "gpu/ipc/common/gpu_stream_constants.h"
 #include "gpu/ipc/common/surface_handle.h"
 #include "ipc/ipc_listener.h"
 #include "ui/gfx/swap_result.h"
@@ -83,7 +83,7 @@
       gpu::SurfaceHandle surface_handle,
       CommandBufferProxyImpl* share_group,
       int32_t stream_id,
-      gpu::GpuStreamPriority stream_priority,
+      gpu::SchedulingPriority stream_priority,
       const gpu::gles2::ContextCreationAttribHelper& attribs,
       const GURL& active_url,
       scoped_refptr<base::SingleThreadTaskRunner> task_runner);
diff --git a/gpu/ipc/client/gpu_channel_host.cc b/gpu/ipc/client/gpu_channel_host.cc
index aa22cdc6..50f9e78 100644
--- a/gpu/ipc/client/gpu_channel_host.cc
+++ b/gpu/ipc/client/gpu_channel_host.cc
@@ -70,7 +70,6 @@
       gpu_memory_buffer_manager_(gpu_memory_buffer_manager) {
   next_image_id_.GetNext();
   next_route_id_.GetNext();
-  next_stream_id_.GetNext();
 }
 
 void GpuChannelHost::Connect(const IPC::ChannelHandle& channel_handle,
@@ -245,13 +244,6 @@
   return next_route_id_.GetNext();
 }
 
-int32_t GpuChannelHost::GenerateStreamID() {
-  const int32_t stream_id = next_stream_id_.GetNext();
-  DCHECK_NE(gpu::GPU_STREAM_INVALID, stream_id);
-  DCHECK_NE(gpu::GPU_STREAM_DEFAULT, stream_id);
-  return stream_id;
-}
-
 uint32_t GpuChannelHost::ValidateFlushIDReachedServer(int32_t stream_id,
                                                       bool force_validate) {
   // Store what flush ids we will be validating for all streams.
diff --git a/gpu/ipc/client/gpu_channel_host.h b/gpu/ipc/client/gpu_channel_host.h
index 88733e79..3fba6d5 100644
--- a/gpu/ipc/client/gpu_channel_host.h
+++ b/gpu/ipc/client/gpu_channel_host.h
@@ -20,7 +20,6 @@
 #include "base/synchronization/lock.h"
 #include "gpu/config/gpu_info.h"
 #include "gpu/gpu_export.h"
-#include "gpu/ipc/common/gpu_stream_constants.h"
 #include "ipc/ipc_channel_handle.h"
 #include "ipc/ipc_sync_channel.h"
 #include "ipc/message_filter.h"
@@ -150,9 +149,6 @@
   // Generate a route ID guaranteed to be unique for this channel.
   int32_t GenerateRouteID();
 
-  // Generate a stream ID guaranteed to be unique for this channel.
-  int32_t GenerateStreamID();
-
   // Sends a synchronous nop to the server which validate that all previous IPC
   // messages have been received. Once the synchronous nop has been sent to the
   // server all previous flushes will all be marked as validated, including
@@ -250,7 +246,6 @@
   // except:
   // - |next_image_id_|, atomic type
   // - |next_route_id_|, atomic type
-  // - |next_stream_id_|, atomic type
   // - |channel_| and |stream_flush_info_|, protected by |context_lock_|
   GpuChannelHostFactory* const factory_;
 
@@ -270,9 +265,6 @@
   // Route IDs are allocated in sequence.
   base::AtomicSequenceNumber next_route_id_;
 
-  // Stream IDs are allocated in sequence.
-  base::AtomicSequenceNumber next_stream_id_;
-
   // Protects channel_ and stream_flush_info_.
   mutable base::Lock context_lock_;
   std::unique_ptr<IPC::SyncChannel> channel_;
diff --git a/gpu/ipc/common/BUILD.gn b/gpu/ipc/common/BUILD.gn
index 25f9a6e..c11f262 100644
--- a/gpu/ipc/common/BUILD.gn
+++ b/gpu/ipc/common/BUILD.gn
@@ -73,7 +73,6 @@
     "gpu_param_traits.cc",
     "gpu_param_traits.h",
     "gpu_param_traits_macros.h",
-    "gpu_stream_constants.h",
     "memory_stats.cc",
     "memory_stats.h",
   ]
diff --git a/gpu/ipc/common/gpu_messages.h b/gpu/ipc/common/gpu_messages.h
index 59b5c49..8243c47 100644
--- a/gpu/ipc/common/gpu_messages.h
+++ b/gpu/ipc/common/gpu_messages.h
@@ -56,7 +56,7 @@
   IPC_STRUCT_MEMBER(gpu::SurfaceHandle, surface_handle)
   IPC_STRUCT_MEMBER(int32_t, share_group_id)
   IPC_STRUCT_MEMBER(int32_t, stream_id)
-  IPC_STRUCT_MEMBER(gpu::GpuStreamPriority, stream_priority)
+  IPC_STRUCT_MEMBER(gpu::SchedulingPriority, stream_priority)
   IPC_STRUCT_MEMBER(gpu::gles2::ContextCreationAttribHelper, attribs)
   IPC_STRUCT_MEMBER(GURL, active_url)
 IPC_STRUCT_END()
diff --git a/gpu/ipc/common/gpu_param_traits_macros.h b/gpu/ipc/common/gpu_param_traits_macros.h
index 0b1ebc4..936ae90 100644
--- a/gpu/ipc/common/gpu_param_traits_macros.h
+++ b/gpu/ipc/common/gpu_param_traits_macros.h
@@ -7,10 +7,10 @@
 
 #include "gpu/command_buffer/common/constants.h"
 #include "gpu/command_buffer/common/gpu_memory_allocation.h"
+#include "gpu/command_buffer/common/scheduling_priority.h"
 #include "gpu/config/gpu_feature_info.h"
 #include "gpu/config/gpu_info.h"
 #include "gpu/gpu_export.h"
-#include "gpu/ipc/common/gpu_stream_constants.h"
 #include "ipc/ipc_message_macros.h"
 #include "ui/gfx/ipc/geometry/gfx_param_traits.h"
 #include "ui/gfx/ipc/gfx_param_traits.h"
@@ -38,7 +38,8 @@
   IPC_STRUCT_TRAITS_MEMBER(max_framerate_denominator)
 IPC_STRUCT_TRAITS_END()
 
-IPC_ENUM_TRAITS_MAX_VALUE(gpu::GpuStreamPriority, gpu::GpuStreamPriority::LAST)
+IPC_ENUM_TRAITS_MAX_VALUE(gpu::SchedulingPriority,
+                          gpu::SchedulingPriority::kLast)
 IPC_ENUM_TRAITS_MAX_VALUE(gpu::MemoryAllocation::PriorityCutoff,
                           gpu::MemoryAllocation::CUTOFF_LAST)
 IPC_ENUM_TRAITS_MAX_VALUE(gpu::error::ContextLostReason,
diff --git a/gpu/ipc/common/gpu_preferences.mojom b/gpu/ipc/common/gpu_preferences.mojom
index e1565ec7..ed4e9d9 100644
--- a/gpu/ipc/common/gpu_preferences.mojom
+++ b/gpu/ipc/common/gpu_preferences.mojom
@@ -18,6 +18,7 @@
   bool single_process;
   bool in_process_gpu;
   bool ui_prioritize_in_gpu_process;
+  bool enable_gpu_scheduler;
   bool disable_accelerated_video_decode;
 
   bool disable_vaapi_accelerated_video_encode;
diff --git a/gpu/ipc/common/gpu_preferences_struct_traits.h b/gpu/ipc/common/gpu_preferences_struct_traits.h
index 0f2a121e..15f5bbd 100644
--- a/gpu/ipc/common/gpu_preferences_struct_traits.h
+++ b/gpu/ipc/common/gpu_preferences_struct_traits.h
@@ -55,6 +55,7 @@
     out->single_process = prefs.single_process();
     out->in_process_gpu = prefs.in_process_gpu();
     out->ui_prioritize_in_gpu_process = prefs.ui_prioritize_in_gpu_process();
+    out->enable_gpu_scheduler = prefs.enable_gpu_scheduler();
     out->disable_accelerated_video_decode =
         prefs.disable_accelerated_video_decode();
 
@@ -114,6 +115,9 @@
   static bool ui_prioritize_in_gpu_process(const gpu::GpuPreferences& prefs) {
     return prefs.ui_prioritize_in_gpu_process;
   }
+  static bool enable_gpu_scheduler(const gpu::GpuPreferences& prefs) {
+    return prefs.enable_gpu_scheduler;
+  }
   static bool disable_accelerated_video_decode(
       const gpu::GpuPreferences& prefs) {
     return prefs.disable_accelerated_video_decode;
diff --git a/gpu/ipc/common/gpu_stream_constants.h b/gpu/ipc/common/gpu_stream_constants.h
deleted file mode 100644
index abab3989..0000000
--- a/gpu/ipc/common/gpu_stream_constants.h
+++ /dev/null
@@ -1,16 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef GPU_IPC_COMMON_GPU_STREAM_CONSTANTS_H_
-#define GPU_IPC_COMMON_GPU_STREAM_CONSTANTS_H_
-
-namespace gpu {
-
-enum class GpuStreamPriority { REAL_TIME, HIGH, NORMAL, LOW, LAST = LOW };
-
-enum GpuStreamId { GPU_STREAM_DEFAULT = -1, GPU_STREAM_INVALID = 0 };
-
-}  // namespace gpu
-
-#endif  // GPU_IPC_COMMON_GPU_STREAM_CONSTANTS_H_
diff --git a/gpu/ipc/common/struct_traits_unittest.cc b/gpu/ipc/common/struct_traits_unittest.cc
index 93adcb2d..0c94f78 100644
--- a/gpu/ipc/common/struct_traits_unittest.cc
+++ b/gpu/ipc/common/struct_traits_unittest.cc
@@ -430,6 +430,7 @@
   prefs.single_process = true;
   prefs.in_process_gpu = true;
   prefs.ui_prioritize_in_gpu_process = true;
+  prefs.enable_gpu_scheduler = true;
 #if defined(OS_WIN)
   const GpuPreferences::VpxDecodeVendors vendor =
       GpuPreferences::VPX_VENDOR_AMD;
@@ -443,6 +444,7 @@
   EXPECT_TRUE(echo.single_process);
   EXPECT_TRUE(echo.in_process_gpu);
   EXPECT_TRUE(echo.ui_prioritize_in_gpu_process);
+  EXPECT_TRUE(echo.enable_gpu_scheduler);
   EXPECT_TRUE(echo.enable_gpu_driver_debug_logging);
 #if defined(OS_WIN)
   EXPECT_EQ(vendor, echo.enable_accelerated_vpx_decode);
diff --git a/gpu/ipc/service/gpu_channel.cc b/gpu/ipc/service/gpu_channel.cc
index 1d67b33..37781d4 100644
--- a/gpu/ipc/service/gpu_channel.cc
+++ b/gpu/ipc/service/gpu_channel.cc
@@ -34,6 +34,7 @@
 #include "gpu/command_buffer/service/image_factory.h"
 #include "gpu/command_buffer/service/mailbox_manager.h"
 #include "gpu/command_buffer/service/preemption_flag.h"
+#include "gpu/command_buffer/service/scheduler.h"
 #include "gpu/ipc/common/gpu_messages.h"
 #include "gpu/ipc/service/gpu_channel_manager.h"
 #include "gpu/ipc/service/gpu_channel_manager_delegate.h"
@@ -99,21 +100,20 @@
 
 GpuChannelMessageQueue::GpuChannelMessageQueue(
     GpuChannel* channel,
+    scoped_refptr<SyncPointOrderData> sync_point_order_data,
     scoped_refptr<base::SingleThreadTaskRunner> main_task_runner,
     scoped_refptr<base::SingleThreadTaskRunner> io_task_runner,
     scoped_refptr<PreemptionFlag> preempting_flag,
-    scoped_refptr<PreemptionFlag> preempted_flag,
-    SyncPointManager* sync_point_manager)
+    scoped_refptr<PreemptionFlag> preempted_flag)
     : channel_(channel),
       max_preemption_time_(
           base::TimeDelta::FromMilliseconds(kMaxPreemptTimeMs)),
       timer_(new base::OneShotTimer),
-      sync_point_order_data_(sync_point_manager->CreateSyncPointOrderData()),
+      sync_point_order_data_(std::move(sync_point_order_data)),
       main_task_runner_(std::move(main_task_runner)),
       io_task_runner_(std::move(io_task_runner)),
       preempting_flag_(std::move(preempting_flag)),
-      preempted_flag_(std::move(preempted_flag)),
-      sync_point_manager_(sync_point_manager) {
+      preempted_flag_(std::move(preempted_flag)) {
   timer_->SetTaskRunner(io_task_runner_);
   io_thread_checker_.DetachFromThread();
 }
@@ -123,20 +123,6 @@
 }
 
 void GpuChannelMessageQueue::Destroy() {
-  // We guarantee that the queue will no longer be modified after Destroy is
-  // called, it is now safe to modify the queue without the lock. All public
-  // facing modifying functions check enabled_ while all private modifying
-  // functions DCHECK(enabled_) to enforce this.
-  while (!channel_messages_.empty()) {
-    const IPC::Message& msg = channel_messages_.front()->message;
-    if (msg.is_sync()) {
-      IPC::Message* reply = IPC::SyncMessage::GenerateReply(&msg);
-      reply->set_reply_error();
-      channel_->Send(reply);
-    }
-    channel_messages_.pop_front();
-  }
-
   sync_point_order_data_->Destroy();
 
   if (preempting_flag_)
@@ -439,9 +425,11 @@
 
 GpuChannelMessageFilter::GpuChannelMessageFilter(
     GpuChannel* gpu_channel,
+    Scheduler* scheduler,
     scoped_refptr<GpuChannelMessageQueue> message_queue,
     scoped_refptr<base::SingleThreadTaskRunner> main_task_runner)
     : gpu_channel_(gpu_channel),
+      scheduler_(scheduler),
       message_queue_(std::move(message_queue)),
       main_task_runner_(std::move(main_task_runner)) {}
 
@@ -454,6 +442,21 @@
   gpu_channel_ = nullptr;
 }
 
+void GpuChannelMessageFilter::AddRoute(int32_t route_id,
+                                       SequenceId sequence_id) {
+  base::AutoLock auto_lock(gpu_channel_lock_);
+  DCHECK(gpu_channel_);
+  DCHECK(scheduler_);
+  route_sequences_[route_id] = sequence_id;
+}
+
+void GpuChannelMessageFilter::RemoveRoute(int32_t route_id) {
+  base::AutoLock auto_lock(gpu_channel_lock_);
+  DCHECK(gpu_channel_);
+  DCHECK(scheduler_);
+  route_sequences_.erase(route_id);
+}
+
 void GpuChannelMessageFilter::OnFilterAdded(IPC::Channel* channel) {
   DCHECK(!ipc_channel_);
   ipc_channel_ = channel;
@@ -504,6 +507,9 @@
 bool GpuChannelMessageFilter::OnMessageReceived(const IPC::Message& message) {
   DCHECK(ipc_channel_);
 
+  if (!gpu_channel_)
+    return MessageErrorHandler(message, "Channel destroyed");
+
   if (message.should_unblock() || message.is_reply())
     return MessageErrorHandler(message, "Unexpected message type");
 
@@ -530,6 +536,23 @@
     main_task_runner_->PostTask(FROM_HERE,
                                 base::Bind(&GpuChannel::HandleOutOfOrderMessage,
                                            gpu_channel_->AsWeakPtr(), message));
+  } else if (scheduler_) {
+    SequenceId sequence_id = route_sequences_[message.routing_id()];
+    if (sequence_id.is_null())
+      return MessageErrorHandler(message, "Invalid route");
+
+    std::vector<SyncToken> sync_token_fences;
+    if (message.type() == GpuCommandBufferMsg_AsyncFlush::ID) {
+      GpuCommandBufferMsg_AsyncFlush::Param params;
+      if (!GpuCommandBufferMsg_AsyncFlush::Read(&message, &params))
+        return MessageErrorHandler(message, "Invalid flush message");
+      sync_token_fences = std::get<3>(params);
+    }
+
+    scheduler_->ScheduleTask(sequence_id,
+                             base::BindOnce(&GpuChannel::HandleMessage,
+                                            gpu_channel_->AsWeakPtr(), message),
+                             sync_token_fences);
   } else {
     // Message queue takes care of PostTask.
     message_queue_->PushBackMessage(message);
@@ -561,6 +584,7 @@
 
 GpuChannel::GpuChannel(
     GpuChannelManager* gpu_channel_manager,
+    Scheduler* scheduler,
     SyncPointManager* sync_point_manager,
     GpuWatchdogThread* watchdog,
     scoped_refptr<gl::GLShareGroup> share_group,
@@ -573,6 +597,7 @@
     uint64_t client_tracing_id,
     bool is_gpu_host)
     : gpu_channel_manager_(gpu_channel_manager),
+      scheduler_(scheduler),
       sync_point_manager_(sync_point_manager),
       preempting_flag_(preempting_flag),
       preempted_flag_(preempted_flag),
@@ -585,14 +610,17 @@
       watchdog_(watchdog),
       is_gpu_host_(is_gpu_host),
       weak_factory_(this) {
-  DCHECK(gpu_channel_manager);
-  DCHECK(client_id);
+  DCHECK(gpu_channel_manager_);
+  DCHECK(client_id_);
 
-  message_queue_ = new GpuChannelMessageQueue(this, task_runner, io_task_runner,
-                                              preempting_flag, preempted_flag,
-                                              sync_point_manager);
+  if (!scheduler_) {
+    message_queue_ = new GpuChannelMessageQueue(
+        this, sync_point_manager->CreateSyncPointOrderData(), task_runner,
+        io_task_runner, preempting_flag, preempted_flag);
+  }
 
-  filter_ = new GpuChannelMessageFilter(this, message_queue_, task_runner);
+  filter_ =
+      new GpuChannelMessageFilter(this, scheduler, message_queue_, task_runner);
 }
 
 GpuChannel::~GpuChannel() {
@@ -602,7 +630,12 @@
   // Destroy filter first so that no message queue gets no more messages.
   filter_->Destroy();
 
-  message_queue_->Destroy();
+  if (scheduler_) {
+    for (const auto& kv : stream_sequences_)
+      scheduler_->DestroySequence(kv.second);
+  } else {
+    message_queue_->Destroy();
+  }
 
   DCHECK(!preempting_flag_ || !preempting_flag_->IsSet());
 }
@@ -656,13 +689,19 @@
 }
 
 void GpuChannel::OnCommandBufferScheduled(GpuCommandBufferStub* stub) {
-  message_queue_->SetScheduled(true);
-  // TODO(sunnyps): Enable gpu scheduler task queue for stub's sequence.
+  if (scheduler_) {
+    scheduler_->EnableSequence(stub->sequence_id());
+  } else {
+    message_queue_->SetScheduled(true);
+  }
 }
 
 void GpuChannel::OnCommandBufferDescheduled(GpuCommandBufferStub* stub) {
-  message_queue_->SetScheduled(false);
-  // TODO(sunnyps): Disable gpu scheduler task queue for stub's sequence.
+  if (scheduler_) {
+    scheduler_->DisableSequence(stub->sequence_id());
+  } else {
+    message_queue_->SetScheduled(false);
+  }
 }
 
 GpuCommandBufferStub* GpuChannel::LookupCommandBuffer(int32_t route_id) {
@@ -685,11 +724,14 @@
 bool GpuChannel::AddRoute(int32_t route_id,
                           SequenceId sequence_id,
                           IPC::Listener* listener) {
-  // TODO(sunnyps): Add route id to sequence id mapping to filter.
+  if (scheduler_)
+    filter_->AddRoute(route_id, sequence_id);
   return router_.AddRoute(route_id, listener);
 }
 
 void GpuChannel::RemoveRoute(int32_t route_id) {
+  if (scheduler_)
+    filter_->RemoveRoute(route_id);
   router_.RemoveRoute(route_id);
 }
 
@@ -707,6 +749,27 @@
   return handled;
 }
 
+void GpuChannel::HandleMessage(const IPC::Message& msg) {
+  int32_t routing_id = msg.routing_id();
+  GpuCommandBufferStub* stub = LookupCommandBuffer(routing_id);
+
+  DCHECK(!stub || stub->IsScheduled());
+
+  DVLOG(1) << "received message @" << &msg << " on channel @" << this
+           << " with type " << msg.type();
+
+  HandleMessageHelper(msg);
+
+  // If we get descheduled or yield while processing a message.
+  if (stub && (stub->HasUnprocessedCommands() || !stub->IsScheduled())) {
+    DCHECK((uint32_t)GpuCommandBufferMsg_AsyncFlush::ID == msg.type() ||
+           (uint32_t)GpuCommandBufferMsg_WaitSyncToken::ID == msg.type());
+    scheduler_->ContinueTask(
+        stub->sequence_id(),
+        base::BindOnce(&GpuChannel::HandleMessage, AsWeakPtr(), msg));
+  }
+}
+
 void GpuChannel::HandleMessageOnQueue() {
   const GpuChannelMessage* channel_msg =
       message_queue_->BeginMessageProcessing();
@@ -799,7 +862,7 @@
     std::unique_ptr<base::SharedMemory> shared_state_shm) {
   if (init_params.surface_handle != kNullSurfaceHandle && !is_gpu_host_) {
     DLOG(ERROR) << "GpuChannel::CreateCommandBuffer(): attempt to create a "
-                   "view context on a non-priviledged channel";
+                   "view context on a non-privileged channel";
     return nullptr;
   }
 
@@ -818,10 +881,10 @@
     return nullptr;
   }
 
-  GpuStreamPriority stream_priority = init_params.stream_priority;
-  if (stream_priority == GpuStreamPriority::REAL_TIME && !is_gpu_host_) {
-    DLOG(ERROR) << "GpuChannel::CreateCommandBuffer(): real time stream "
-                   "priority not allowed";
+  SchedulingPriority stream_priority = init_params.stream_priority;
+  if (stream_priority <= SchedulingPriority::kHigh && !is_gpu_host_) {
+    DLOG(ERROR) << "GpuChannel::CreateCommandBuffer(): high priority stream "
+                   "not allowed on a non-privileged channel";
     return nullptr;
   }
 
@@ -842,8 +905,16 @@
   CommandBufferId command_buffer_id =
       GenerateCommandBufferId(client_id_, route_id);
 
-  // TODO(sunnyps): Lookup sequence id using stream id to sequence id map.
-  SequenceId sequence_id = message_queue_->sequence_id();
+  SequenceId sequence_id;
+  if (scheduler_) {
+    sequence_id = stream_sequences_[stream_id];
+    if (sequence_id.is_null()) {
+      sequence_id = scheduler_->CreateSequence(stream_priority);
+      stream_sequences_[stream_id] = sequence_id;
+    }
+  } else {
+    sequence_id = message_queue_->sequence_id();
+  }
 
   std::unique_ptr<GpuCommandBufferStub> stub(GpuCommandBufferStub::Create(
       this, share_group, init_params, command_buffer_id, sequence_id, stream_id,
diff --git a/gpu/ipc/service/gpu_channel.h b/gpu/ipc/service/gpu_channel.h
index bd583b2..ee8d161 100644
--- a/gpu/ipc/service/gpu_channel.h
+++ b/gpu/ipc/service/gpu_channel.h
@@ -10,9 +10,8 @@
 
 #include <memory>
 #include <string>
-#include <unordered_map>
 
-#include "base/containers/hash_tables.h"
+#include "base/containers/flat_map.h"
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
@@ -22,7 +21,6 @@
 #include "build/build_config.h"
 #include "gpu/command_buffer/service/sync_point_manager.h"
 #include "gpu/gpu_export.h"
-#include "gpu/ipc/common/gpu_stream_constants.h"
 #include "gpu/ipc/service/gpu_command_buffer_stub.h"
 #include "gpu/ipc/service/gpu_memory_manager.h"
 #include "ipc/ipc_sender.h"
@@ -42,6 +40,7 @@
 namespace gpu {
 
 class PreemptionFlag;
+class Scheduler;
 class SyncPointManager;
 class GpuChannelManager;
 class GpuChannelMessageFilter;
@@ -82,6 +81,7 @@
  public:
   // Takes ownership of the renderer process handle.
   GpuChannel(GpuChannelManager* gpu_channel_manager,
+             Scheduler* scheduler,
              SyncPointManager* sync_point_manager,
              GpuWatchdogThread* watchdog,
              scoped_refptr<gl::GLShareGroup> share_group,
@@ -99,6 +99,8 @@
   // listener. The listener is the GpuChannel and must be constructed first.
   void Init(std::unique_ptr<FilteredSender> channel);
 
+  base::WeakPtr<GpuChannel> AsWeakPtr();
+
   void SetUnhandledMessageListener(IPC::Listener* listener);
 
   // Get the GpuChannelManager that owns this channel.
@@ -106,6 +108,8 @@
     return gpu_channel_manager_;
   }
 
+  Scheduler* scheduler() const { return scheduler_; }
+
   SyncPointManager* sync_point_manager() const { return sync_point_manager_; }
 
   GpuWatchdogThread* watchdog() const { return watchdog_; }
@@ -132,8 +136,6 @@
 
   uint64_t client_tracing_id() const { return client_tracing_id_; }
 
-  base::WeakPtr<GpuChannel> AsWeakPtr();
-
   const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner() const {
     return io_task_runner_;
   }
@@ -180,6 +182,8 @@
       uint32_t internalformat,
       SurfaceHandle surface_handle);
 
+  void HandleMessage(const IPC::Message& msg);
+
   // Handle messages enqueued in |message_queue_|.
   void HandleMessageOnQueue();
 
@@ -222,13 +226,18 @@
   scoped_refptr<GpuChannelMessageFilter> filter_;
 
   // Map of routing id to command buffer stub.
-  std::unordered_map<int32_t, std::unique_ptr<GpuCommandBufferStub>> stubs_;
+  base::flat_map<int32_t, std::unique_ptr<GpuCommandBufferStub>> stubs_;
+
+  // Map of stream id to scheduler sequence id.
+  base::flat_map<int32_t, SequenceId> stream_sequences_;
 
   // The lifetime of objects of this class is managed by a GpuChannelManager.
   // The GpuChannelManager destroy all the GpuChannels that they own when they
   // are destroyed. So a raw pointer is safe.
   GpuChannelManager* const gpu_channel_manager_;
 
+  Scheduler* const scheduler_;
+
   // Sync point manager. Outlives the channel and is guaranteed to outlive the
   // message loop.
   SyncPointManager* const sync_point_manager_;
@@ -274,26 +283,27 @@
   DISALLOW_COPY_AND_ASSIGN(GpuChannel);
 };
 
-// This filter does three things:
-// - it counts and timestamps each message forwarded to the channel
-//   so that we can preempt other channels if a message takes too long to
-//   process. To guarantee fairness, we must wait a minimum amount of time
-//   before preempting and we limit the amount of time that we can preempt in
-//   one shot (see constants above).
-// - it handles the GpuCommandBufferMsg_InsertSyncPoint message on the IO
-//   thread, generating the sync point ID and responding immediately, and then
-//   posting a task to insert the GpuCommandBufferMsg_RetireSyncPoint message
-//   into the channel's queue.
-// - it generates mailbox names for clients of the GPU process on the IO thread.
+// This filter does the following:
+// - handles the Nop message used for verifying sync tokens on the IO thread
+// - forwards messages to child message filters
+// - posts control and out of order messages to the main thread
+// - forwards other messages to the message queue or the scheduler
 class GPU_EXPORT GpuChannelMessageFilter : public IPC::MessageFilter {
  public:
   GpuChannelMessageFilter(
       GpuChannel* gpu_channel,
+      Scheduler* scheduler,
       scoped_refptr<GpuChannelMessageQueue> message_queue,
       scoped_refptr<base::SingleThreadTaskRunner> main_task_runner);
 
+  // Methods called on main thread.
   void Destroy();
 
+  // Called when scheduler is enabled.
+  void AddRoute(int32_t route_id, SequenceId sequence_id);
+  void RemoveRoute(int32_t route_id);
+
+  // Methods called on IO thread.
   // IPC::MessageFilter implementation.
   void OnFilterAdded(IPC::Channel* channel) override;
   void OnFilterRemoved() override;
@@ -317,8 +327,11 @@
   std::vector<scoped_refptr<IPC::MessageFilter>> channel_filters_;
 
   GpuChannel* gpu_channel_ = nullptr;
-  base::Lock gpu_channel_lock_;
+  // Map of route id to scheduler sequence id.
+  base::flat_map<int32_t, SequenceId> route_sequences_;
+  mutable base::Lock gpu_channel_lock_;
 
+  Scheduler* scheduler_;
   scoped_refptr<GpuChannelMessageQueue> message_queue_;
   scoped_refptr<base::SingleThreadTaskRunner> main_task_runner_;
 
@@ -339,16 +352,21 @@
   DISALLOW_COPY_AND_ASSIGN(GpuChannelMessage);
 };
 
+// This message queue counts and timestamps each message forwarded to the
+// channel so that we can preempt other channels if a message takes too long to
+// process. To guarantee fairness, we must wait a minimum amount of time before
+// preempting and we limit the amount of time that we can preempt in one shot
+// (see constants above).
 class GpuChannelMessageQueue
     : public base::RefCountedThreadSafe<GpuChannelMessageQueue> {
  public:
   GpuChannelMessageQueue(
       GpuChannel* channel,
+      scoped_refptr<SyncPointOrderData> sync_point_order_data,
       scoped_refptr<base::SingleThreadTaskRunner> main_task_runner,
       scoped_refptr<base::SingleThreadTaskRunner> io_task_runner,
       scoped_refptr<PreemptionFlag> preempting_flag,
-      scoped_refptr<PreemptionFlag> preempted_flag,
-      SyncPointManager* sync_point_manager);
+      scoped_refptr<PreemptionFlag> preempted_flag);
 
   void Destroy();
 
@@ -359,8 +377,6 @@
   bool IsScheduled() const;
   void SetScheduled(bool scheduled);
 
-  bool HasQueuedMessages() const;
-
   // Should be called before a message begins to be processed. Returns false if
   // there are no messages to process.
   const GpuChannelMessage* BeginMessageProcessing();
@@ -438,7 +454,6 @@
   scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_;
   scoped_refptr<PreemptionFlag> preempting_flag_;
   scoped_refptr<PreemptionFlag> preempted_flag_;
-  SyncPointManager* const sync_point_manager_;
 
   DISALLOW_COPY_AND_ASSIGN(GpuChannelMessageQueue);
 };
diff --git a/gpu/ipc/service/gpu_channel_manager.cc b/gpu/ipc/service/gpu_channel_manager.cc
index 31dd3369..96785707 100644
--- a/gpu/ipc/service/gpu_channel_manager.cc
+++ b/gpu/ipc/service/gpu_channel_manager.cc
@@ -20,6 +20,7 @@
 #include "gpu/command_buffer/service/mailbox_manager.h"
 #include "gpu/command_buffer/service/memory_program_cache.h"
 #include "gpu/command_buffer/service/preemption_flag.h"
+#include "gpu/command_buffer/service/scheduler.h"
 #include "gpu/command_buffer/service/shader_translator_cache.h"
 #include "gpu/command_buffer/service/sync_point_manager.h"
 #include "gpu/ipc/common/gpu_messages.h"
@@ -41,7 +42,6 @@
 // draw.
 const int kMaxKeepAliveTimeMs = 200;
 #endif
-
 }
 
 GpuChannelManager::GpuChannelManager(
@@ -51,6 +51,7 @@
     GpuWatchdogThread* watchdog,
     scoped_refptr<base::SingleThreadTaskRunner> task_runner,
     scoped_refptr<base::SingleThreadTaskRunner> io_task_runner,
+    Scheduler* scheduler,
     SyncPointManager* sync_point_manager,
     GpuMemoryBufferFactory* gpu_memory_buffer_factory,
     const GpuFeatureInfo& gpu_feature_info,
@@ -64,6 +65,7 @@
       share_group_(new gl::GLShareGroup()),
       mailbox_manager_(gles2::MailboxManager::Create(gpu_preferences)),
       gpu_memory_manager_(this),
+      scheduler_(scheduler),
       sync_point_manager_(sync_point_manager),
       gpu_memory_buffer_factory_(gpu_memory_buffer_factory),
       gpu_feature_info_(gpu_feature_info),
@@ -72,7 +74,7 @@
       weak_factory_(this) {
   DCHECK(task_runner);
   DCHECK(io_task_runner);
-  if (gpu_preferences_.ui_prioritize_in_gpu_process)
+  if (gpu_preferences.ui_prioritize_in_gpu_process)
     preemption_flag_ = new PreemptionFlag;
 }
 
@@ -100,8 +102,7 @@
   return program_cache_.get();
 }
 
-gles2::ShaderTranslatorCache*
-GpuChannelManager::shader_translator_cache() {
+gles2::ShaderTranslatorCache* GpuChannelManager::shader_translator_cache() {
   if (!shader_translator_cache_.get()) {
     shader_translator_cache_ =
         new gles2::ShaderTranslatorCache(gpu_preferences_);
@@ -112,8 +113,7 @@
 gles2::FramebufferCompletenessCache*
 GpuChannelManager::framebuffer_completeness_cache() {
   if (!framebuffer_completeness_cache_.get())
-    framebuffer_completeness_cache_ =
-        new gles2::FramebufferCompletenessCache;
+    framebuffer_completeness_cache_ = new gles2::FramebufferCompletenessCache;
   return framebuffer_completeness_cache_.get();
 }
 
@@ -131,8 +131,8 @@
                                                 uint64_t client_tracing_id,
                                                 bool is_gpu_host) {
   std::unique_ptr<GpuChannel> gpu_channel = base::MakeUnique<GpuChannel>(
-      this, sync_point_manager_, watchdog_, share_group_, mailbox_manager_,
-      is_gpu_host ? preemption_flag_ : nullptr,
+      this, scheduler_, sync_point_manager_, watchdog_, share_group_,
+      mailbox_manager_, is_gpu_host ? preemption_flag_ : nullptr,
       is_gpu_host ? nullptr : preemption_flag_, task_runner_, io_task_runner_,
       client_id, client_tracing_id, is_gpu_host);
 
@@ -156,10 +156,9 @@
   gpu_memory_buffer_factory_->DestroyGpuMemoryBuffer(id, client_id);
 }
 
-void GpuChannelManager::DestroyGpuMemoryBuffer(
-    gfx::GpuMemoryBufferId id,
-    int client_id,
-    const SyncToken& sync_token) {
+void GpuChannelManager::DestroyGpuMemoryBuffer(gfx::GpuMemoryBufferId id,
+                                               int client_id,
+                                               const SyncToken& sync_token) {
   if (!sync_point_manager_->WaitOutOfOrder(
           sync_token,
           base::Bind(&GpuChannelManager::InternalDestroyGpuMemoryBuffer,
@@ -218,8 +217,8 @@
 
 void GpuChannelManager::ScheduleWakeUpGpu() {
   base::TimeTicks now = base::TimeTicks::Now();
-  TRACE_EVENT2("gpu", "GpuChannelManager::ScheduleWakeUp",
-               "idle_time", (now - last_gpu_access_time_).InMilliseconds(),
+  TRACE_EVENT2("gpu", "GpuChannelManager::ScheduleWakeUp", "idle_time",
+               (now - last_gpu_access_time_).InMilliseconds(),
                "keep_awake_time", (now - begin_wake_up_time_).InMilliseconds());
   if (now - last_gpu_access_time_ <
       base::TimeDelta::FromMilliseconds(kMaxGpuIdleTimeMs))
diff --git a/gpu/ipc/service/gpu_channel_manager.h b/gpu/ipc/service/gpu_channel_manager.h
index b0a183acd..0ce987a 100644
--- a/gpu/ipc/service/gpu_channel_manager.h
+++ b/gpu/ipc/service/gpu_channel_manager.h
@@ -37,6 +37,7 @@
 class GpuDriverBugWorkarounds;
 struct GpuPreferences;
 class PreemptionFlag;
+class Scheduler;
 class SyncPointManager;
 struct SyncToken;
 namespace gles2 {
@@ -64,6 +65,7 @@
                     GpuWatchdogThread* watchdog,
                     scoped_refptr<base::SingleThreadTaskRunner> task_runner,
                     scoped_refptr<base::SingleThreadTaskRunner> io_task_runner,
+                    Scheduler* scheduler,
                     SyncPointManager* sync_point_manager,
                     GpuMemoryBufferFactory* gpu_memory_buffer_factory,
                     const GpuFeatureInfo& gpu_feature_info,
@@ -122,6 +124,8 @@
 
   gl::GLShareGroup* share_group() const { return share_group_.get(); }
 
+  SyncPointManager* sync_point_manager() const { return sync_point_manager_; }
+
  private:
   void InternalDestroyGpuMemoryBuffer(gfx::GpuMemoryBufferId id, int client_id);
   void InternalDestroyGpuMemoryBufferOnIO(gfx::GpuMemoryBufferId id,
@@ -147,9 +151,12 @@
   GpuWatchdogThread* watchdog_;
 
   scoped_refptr<gl::GLShareGroup> share_group_;
-  scoped_refptr<gles2::MailboxManager> mailbox_manager_;
+
   scoped_refptr<PreemptionFlag> preemption_flag_;
+
+  scoped_refptr<gles2::MailboxManager> mailbox_manager_;
   GpuMemoryManager gpu_memory_manager_;
+  Scheduler* scheduler_;
   // SyncPointManager guaranteed to outlive running MessageLoop.
   SyncPointManager* sync_point_manager_;
   std::unique_ptr<gles2::ProgramCache> program_cache_;
diff --git a/gpu/ipc/service/gpu_channel_test_common.cc b/gpu/ipc/service/gpu_channel_test_common.cc
index a236c68..dddbd5da 100644
--- a/gpu/ipc/service/gpu_channel_test_common.cc
+++ b/gpu/ipc/service/gpu_channel_test_common.cc
@@ -79,11 +79,12 @@
           new GpuChannelManager(GpuPreferences(),
                                 GpuDriverBugWorkarounds(),
                                 channel_manager_delegate_.get(),
-                                nullptr /* watchdog */,
+                                nullptr, /* watchdog */
                                 task_runner_.get(),
                                 io_task_runner_.get(),
+                                nullptr, /* scheduler */
                                 sync_point_manager_.get(),
-                                nullptr /* gpu_memory_buffer_factory */,
+                                nullptr, /* gpu_memory_buffer_factory */
                                 GpuFeatureInfo(),
                                 GpuProcessActivityFlags())) {
   // We need GL bindings to actually initialize command buffers.
diff --git a/gpu/ipc/service/gpu_channel_unittest.cc b/gpu/ipc/service/gpu_channel_unittest.cc
index e76f2db..286124a 100644
--- a/gpu/ipc/service/gpu_channel_unittest.cc
+++ b/gpu/ipc/service/gpu_channel_unittest.cc
@@ -32,7 +32,7 @@
   init_params.surface_handle = surface_handle;
   init_params.share_group_id = MSG_ROUTING_NONE;
   init_params.stream_id = 0;
-  init_params.stream_priority = GpuStreamPriority::NORMAL;
+  init_params.stream_priority = SchedulingPriority::kNormal;
   init_params.attribs = gles2::ContextCreationAttribHelper();
   init_params.active_url = GURL();
   bool result = false;
@@ -60,7 +60,7 @@
   init_params.surface_handle = surface_handle;
   init_params.share_group_id = MSG_ROUTING_NONE;
   init_params.stream_id = 0;
-  init_params.stream_priority = GpuStreamPriority::NORMAL;
+  init_params.stream_priority = SchedulingPriority::kNormal;
   init_params.attribs = gles2::ContextCreationAttribHelper();
   init_params.active_url = GURL();
   bool result = false;
@@ -84,7 +84,7 @@
   init_params.surface_handle = kNullSurfaceHandle;
   init_params.share_group_id = MSG_ROUTING_NONE;
   init_params.stream_id = 0;
-  init_params.stream_priority = GpuStreamPriority::NORMAL;
+  init_params.stream_priority = SchedulingPriority::kNormal;
   init_params.attribs = gles2::ContextCreationAttribHelper();
   init_params.active_url = GURL();
   bool result = false;
@@ -110,7 +110,7 @@
   init_params.surface_handle = kNullSurfaceHandle;
   init_params.share_group_id = MSG_ROUTING_NONE;
   init_params.stream_id = kStreamId1;
-  init_params.stream_priority = GpuStreamPriority::NORMAL;
+  init_params.stream_priority = SchedulingPriority::kNormal;
   init_params.attribs = gles2::ContextCreationAttribHelper();
   init_params.active_url = GURL();
   bool result = false;
@@ -129,7 +129,7 @@
 
   init_params.share_group_id = kRouteId1;
   init_params.stream_id = kStreamId2;
-  init_params.stream_priority = GpuStreamPriority::NORMAL;
+  init_params.stream_priority = SchedulingPriority::kNormal;
   init_params.attribs = gles2::ContextCreationAttribHelper();
   init_params.active_url = GURL();
   HandleMessage(channel, new GpuChannelMsg_CreateCommandBuffer(
@@ -141,21 +141,20 @@
   EXPECT_FALSE(stub);
 }
 
-TEST_F(GpuChannelTest, RealTimeStreamsDisallowed) {
+TEST_F(GpuChannelTest, HighPriorityStreamsDisallowed) {
   int32_t kClientId = 1;
   bool is_gpu_host = false;
   GpuChannel* channel = CreateChannel(kClientId, is_gpu_host);
   ASSERT_TRUE(channel);
 
-  // Create first context.
+  // Highest priority is disallowed.
   int32_t kRouteId = 1;
   int32_t kStreamId = 1;
-  GpuStreamPriority kStreamPriority = GpuStreamPriority::REAL_TIME;
   GPUCreateCommandBufferConfig init_params;
   init_params.surface_handle = kNullSurfaceHandle;
   init_params.share_group_id = MSG_ROUTING_NONE;
   init_params.stream_id = kStreamId;
-  init_params.stream_priority = kStreamPriority;
+  init_params.stream_priority = SchedulingPriority::kHighest;
   init_params.attribs = gles2::ContextCreationAttribHelper();
   init_params.active_url = GURL();
   bool result = false;
@@ -164,37 +163,50 @@
                              init_params, kRouteId, GetSharedHandle(), &result,
                              &capabilities));
   EXPECT_FALSE(result);
+  EXPECT_FALSE(channel->LookupCommandBuffer(kRouteId));
 
-  GpuCommandBufferStub* stub = channel->LookupCommandBuffer(kRouteId);
-  EXPECT_FALSE(stub);
+  // High priority is also disallowed.
+  init_params.stream_priority = SchedulingPriority::kHigh;
+  HandleMessage(channel, new GpuChannelMsg_CreateCommandBuffer(
+                             init_params, kRouteId, GetSharedHandle(), &result,
+                             &capabilities));
+  EXPECT_FALSE(result);
+  EXPECT_FALSE(channel->LookupCommandBuffer(kRouteId));
 }
 
-TEST_F(GpuChannelTest, RealTimeStreamsAllowed) {
+TEST_F(GpuChannelTest, HighPriorityStreamsAllowed) {
   int32_t kClientId = 1;
   bool is_gpu_host = true;
   GpuChannel* channel = CreateChannel(kClientId, is_gpu_host);
   ASSERT_TRUE(channel);
 
-  // Create first context.
-  int32_t kRouteId = 1;
-  int32_t kStreamId = 1;
-  GpuStreamPriority kStreamPriority = GpuStreamPriority::REAL_TIME;
+  // Highest priority is allowed.
+  int32_t kRouteId1 = 1;
   GPUCreateCommandBufferConfig init_params;
   init_params.surface_handle = kNullSurfaceHandle;
   init_params.share_group_id = MSG_ROUTING_NONE;
-  init_params.stream_id = kStreamId;
-  init_params.stream_priority = kStreamPriority;
+  init_params.stream_id = 1;
+  init_params.stream_priority = SchedulingPriority::kHighest;
   init_params.attribs = gles2::ContextCreationAttribHelper();
   init_params.active_url = GURL();
   bool result = false;
   gpu::Capabilities capabilities;
   HandleMessage(channel, new GpuChannelMsg_CreateCommandBuffer(
-                             init_params, kRouteId, GetSharedHandle(), &result,
+                             init_params, kRouteId1, GetSharedHandle(), &result,
                              &capabilities));
   EXPECT_TRUE(result);
+  EXPECT_TRUE(channel->LookupCommandBuffer(kRouteId1));
 
-  GpuCommandBufferStub* stub = channel->LookupCommandBuffer(kRouteId);
-  EXPECT_TRUE(stub);
+  // High priority is also allowed.
+  int32_t kRouteId2 = 2;
+  init_params.stream_id = 2;
+  init_params.stream_priority = SchedulingPriority::kHigh;
+  result = false;
+  HandleMessage(channel, new GpuChannelMsg_CreateCommandBuffer(
+                             init_params, kRouteId2, GetSharedHandle(), &result,
+                             &capabilities));
+  EXPECT_TRUE(result);
+  EXPECT_TRUE(channel->LookupCommandBuffer(kRouteId2));
 }
 
 TEST_F(GpuChannelTest, CreateFailsIfSharedContextIsLost) {
@@ -210,7 +222,7 @@
     init_params.surface_handle = kNullSurfaceHandle;
     init_params.share_group_id = MSG_ROUTING_NONE;
     init_params.stream_id = 0;
-    init_params.stream_priority = GpuStreamPriority::NORMAL;
+    init_params.stream_priority = SchedulingPriority::kNormal;
     init_params.attribs = gles2::ContextCreationAttribHelper();
     init_params.active_url = GURL();
     bool result = false;
@@ -230,7 +242,7 @@
     init_params.surface_handle = kNullSurfaceHandle;
     init_params.share_group_id = kSharedRouteId;
     init_params.stream_id = 0;
-    init_params.stream_priority = GpuStreamPriority::NORMAL;
+    init_params.stream_priority = SchedulingPriority::kNormal;
     init_params.attribs = gles2::ContextCreationAttribHelper();
     init_params.active_url = GURL();
     bool result = false;
@@ -254,7 +266,7 @@
     init_params.surface_handle = kNullSurfaceHandle;
     init_params.share_group_id = kSharedRouteId;
     init_params.stream_id = 0;
-    init_params.stream_priority = GpuStreamPriority::NORMAL;
+    init_params.stream_priority = SchedulingPriority::kNormal;
     init_params.attribs = gles2::ContextCreationAttribHelper();
     init_params.active_url = GURL();
     bool result = false;
diff --git a/gpu/ipc/service/gpu_command_buffer_stub.cc b/gpu/ipc/service/gpu_command_buffer_stub.cc
index d140ddb4..fc4784f 100644
--- a/gpu/ipc/service/gpu_command_buffer_stub.cc
+++ b/gpu/ipc/service/gpu_command_buffer_stub.cc
@@ -31,6 +31,7 @@
 #include "gpu/command_buffer/service/memory_tracking.h"
 #include "gpu/command_buffer/service/preemption_flag.h"
 #include "gpu/command_buffer/service/query_manager.h"
+#include "gpu/command_buffer/service/scheduler.h"
 #include "gpu/command_buffer/service/service_utils.h"
 #include "gpu/command_buffer/service/sync_point_manager.h"
 #include "gpu/command_buffer/service/transfer_buffer_manager.h"
@@ -652,8 +653,11 @@
       channel_->sync_point_manager()->CreateSyncPointClientState(
           CommandBufferNamespace::GPU_IO, command_buffer_id_, sequence_id_);
 
-  // TODO(sunnyps): Hook callback to gpu scheduler.
-  if (channel_->preempted_flag()) {
+  if (channel_->scheduler()) {
+    executor_->SetPauseExecutionCallback(
+        base::Bind(&Scheduler::ShouldYield,
+                   base::Unretained(channel_->scheduler()), sequence_id_));
+  } else if (channel_->preempted_flag()) {
     executor_->SetPauseExecutionCallback(
         base::Bind(&PreemptionFlag::IsSet, channel_->preempted_flag()));
   }
diff --git a/ios/chrome/browser/experimental_flags.h b/ios/chrome/browser/experimental_flags.h
index e358ad63..090152bd 100644
--- a/ios/chrome/browser/experimental_flags.h
+++ b/ios/chrome/browser/experimental_flags.h
@@ -45,9 +45,6 @@
 // Whether auto-reload is enabled.
 bool IsAutoReloadEnabled();
 
-// Whether the external applicaiton prompt is enabled.
-bool IsExternalApplicationPromptEnabled();
-
 // Whether contextual search must be reset to undecided state.
 bool IsForceResetContextualSearchEnabled();
 
diff --git a/ios/chrome/browser/experimental_flags.mm b/ios/chrome/browser/experimental_flags.mm
index 5d5d5b2..67bc6f56 100644
--- a/ios/chrome/browser/experimental_flags.mm
+++ b/ios/chrome/browser/experimental_flags.mm
@@ -33,7 +33,6 @@
 NSString* const kEnableNewClearBrowsingDataUI = @"EnableNewClearBrowsingDataUI";
 NSString* const kEnableStartupCrash = @"EnableStartupCrash";
 NSString* const kEnableViewCopyPasswords = @"EnableViewCopyPasswords";
-NSString* const kExternalAppPromptDisabled = @"ExternalAppPromptDisabled";
 NSString* const kFirstRunForceEnabled = @"FirstRunForceEnabled";
 NSString* const kForceResetContextualSearch = @"ForceResetContextualSearch";
 NSString* const kGaiaEnvironment = @"GAIAEnvironment";
@@ -99,11 +98,6 @@
                           base::CompareCase::INSENSITIVE_ASCII);
 }
 
-bool IsExternalApplicationPromptEnabled() {
-  return ![[NSUserDefaults standardUserDefaults]
-      boolForKey:kExternalAppPromptDisabled];
-}
-
 bool IsForceResetContextualSearchEnabled() {
   return [[NSUserDefaults standardUserDefaults]
       boolForKey:kForceResetContextualSearch];
diff --git a/ios/chrome/browser/resources/Settings.bundle/Experimental.plist b/ios/chrome/browser/resources/Settings.bundle/Experimental.plist
index 93460d4..11727b1 100644
--- a/ios/chrome/browser/resources/Settings.bundle/Experimental.plist
+++ b/ios/chrome/browser/resources/Settings.bundle/Experimental.plist
@@ -378,16 +378,6 @@
 			<key>Type</key>
 			<string>PSToggleSwitchSpecifier</string>
 			<key>Title</key>
-			<string>Disable External Application Prompt</string>
-			<key>Key</key>
-			<string>ExternalAppPromptDisabled</string>
-			<key>DefaultValue</key>
-			<false/>
-		</dict>
-		<dict>
-			<key>Type</key>
-			<string>PSToggleSwitchSpecifier</string>
-			<key>Title</key>
 			<string>Disable Update Password UI</string>
 			<key>Key</key>
 			<string>UpdatePasswordUIDisabled</string>
diff --git a/ios/chrome/browser/web/external_app_launcher.mm b/ios/chrome/browser/web/external_app_launcher.mm
index d10f3d6..20b9664 100644
--- a/ios/chrome/browser/web/external_app_launcher.mm
+++ b/ios/chrome/browser/web/external_app_launcher.mm
@@ -177,15 +177,13 @@
       UIApplicationStateActive)
     return NO;
 
-  if (experimental_flags::IsExternalApplicationPromptEnabled()) {
-    // Prompt user to open itunes when opening it is not a result of a link
-    // click.
-    if (!linkClicked && UrlHasAppStoreScheme(gURL)) {
-      [self performSelector:@selector(openExternalAppWithPromptForURL:)
-                 withObject:URL
-                 afterDelay:0.0];
-      return YES;
-    }
+  // Prompt user to open itunes when opening it is not a result of a link
+  // click.
+  if (!linkClicked && UrlHasAppStoreScheme(gURL)) {
+    [self performSelector:@selector(openExternalAppWithPromptForURL:)
+               withObject:URL
+               afterDelay:0.0];
+    return YES;
   }
 
   // Replaces |URL| with a rewritten URL if it is of mailto: scheme.
diff --git a/ios/web/public/web_state/ui/crw_web_view_scroll_view_proxy.h b/ios/web/public/web_state/ui/crw_web_view_scroll_view_proxy.h
index d677274..a23d0eb1d 100644
--- a/ios/web/public/web_state/ui/crw_web_view_scroll_view_proxy.h
+++ b/ios/web/public/web_state/ui/crw_web_view_scroll_view_proxy.h
@@ -24,6 +24,7 @@
 @interface CRWWebViewScrollViewProxy : NSObject<UIScrollViewDelegate>
 @property(nonatomic, assign) CGPoint contentOffset;
 @property(nonatomic, assign) UIEdgeInsets contentInset;
+@property(nonatomic, readonly, getter=isDecelerating) BOOL decelerating;
 @property(nonatomic, readonly, getter=isDragging) BOOL dragging;
 @property(nonatomic, readonly) BOOL isZooming;
 @property(nonatomic, readonly) CGFloat zoomScale;
@@ -79,6 +80,12 @@
     (CRWWebViewScrollViewProxy*)webViewScrollViewProxy;
 - (void)webViewScrollViewDidResetContentSize:
     (CRWWebViewScrollViewProxy*)webViewScrollViewProxy;
+
+// The equivalent in UIScrollViewDelegate also takes a parameter (UIView*)view,
+// but CRWWebViewScrollViewObserver doesn't expose it for flexibility of future
+// implementation.
+- (void)webViewScrollViewWillBeginZooming:
+    (CRWWebViewScrollViewProxy*)webViewScrollViewProxy;
 @end
 
 // A protocol to be implemented by objects to listen for changes to the
diff --git a/ios/web/web_state/ui/crw_web_view_scroll_view_proxy.mm b/ios/web/web_state/ui/crw_web_view_scroll_view_proxy.mm
index a11229ed..f60a6db6 100644
--- a/ios/web/web_state/ui/crw_web_view_scroll_view_proxy.mm
+++ b/ios/web/web_state/ui/crw_web_view_scroll_view_proxy.mm
@@ -93,6 +93,10 @@
   [_scrollView setBounces:bounces];
 }
 
+- (BOOL)isDecelerating {
+  return [_scrollView isDecelerating];
+}
+
 - (BOOL)isDragging {
   return [_scrollView isDragging];
 }
@@ -209,6 +213,12 @@
   [_observers webViewScrollViewDidZoom:self];
 }
 
+- (void)scrollViewWillBeginZooming:(UIScrollView*)scrollView
+                          withView:(UIView*)view {
+  DCHECK_EQ(_scrollView, scrollView);
+  [_observers webViewScrollViewWillBeginZooming:self];
+}
+
 #pragma mark -
 
 + (NSArray*)scrollViewObserverKeyPaths {
diff --git a/ios/web/web_state/ui/crw_web_view_scroll_view_proxy_unittest.mm b/ios/web/web_state/ui/crw_web_view_scroll_view_proxy_unittest.mm
index f1c17ddd..f5dee07 100644
--- a/ios/web/web_state/ui/crw_web_view_scroll_view_proxy_unittest.mm
+++ b/ios/web/web_state/ui/crw_web_view_scroll_view_proxy_unittest.mm
@@ -102,6 +102,12 @@
       frame];
   EXPECT_TRUE(CGRectEqualToRect(frame, [webViewScrollViewProxy_ frame]));
 
+  [[[mockScrollView_ expect] andReturnValue:@YES] isDecelerating];
+  EXPECT_TRUE([webViewScrollViewProxy_ isDecelerating]);
+
+  [[[mockScrollView_ expect] andReturnValue:@NO] isDecelerating];
+  EXPECT_FALSE([webViewScrollViewProxy_ isDecelerating]);
+
   [[[mockScrollView_ expect] andReturnValue:@YES] isDragging];
   EXPECT_TRUE([webViewScrollViewProxy_ isDragging]);
 
@@ -123,6 +129,7 @@
   EXPECT_TRUE(
       CGSizeEqualToSize(CGSizeZero, [webViewScrollViewProxy_ contentSize]));
   EXPECT_TRUE(CGRectEqualToRect(CGRectZero, [webViewScrollViewProxy_ frame]));
+  EXPECT_FALSE([webViewScrollViewProxy_ isDecelerating]);
   EXPECT_FALSE([webViewScrollViewProxy_ isDragging]);
 
   // Make sure setting the properties is fine too.
diff --git a/media/base/decoder_factory.cc b/media/base/decoder_factory.cc
index dad79469..fa002d6 100644
--- a/media/base/decoder_factory.cc
+++ b/media/base/decoder_factory.cc
@@ -14,11 +14,11 @@
 
 void DecoderFactory::CreateAudioDecoders(
     scoped_refptr<base::SingleThreadTaskRunner> task_runner,
-    ScopedVector<AudioDecoder>* audio_decoders) {}
+    std::vector<std::unique_ptr<AudioDecoder>>* audio_decoders) {}
 
 void DecoderFactory::CreateVideoDecoders(
     scoped_refptr<base::SingleThreadTaskRunner> task_runner,
     GpuVideoAcceleratorFactories* gpu_factories,
-    ScopedVector<VideoDecoder>* video_decoders) {}
+    std::vector<std::unique_ptr<VideoDecoder>>* video_decoders) {}
 
 }  // namespace media
diff --git a/media/base/decoder_factory.h b/media/base/decoder_factory.h
index 06df353..4d90ee3 100644
--- a/media/base/decoder_factory.h
+++ b/media/base/decoder_factory.h
@@ -5,9 +5,11 @@
 #ifndef MEDIA_BASE_DECODER_FACTORY_H_
 #define MEDIA_BASE_DECODER_FACTORY_H_
 
+#include <memory>
+#include <vector>
+
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
-#include "base/memory/scoped_vector.h"
 #include "media/base/media_export.h"
 
 namespace base {
@@ -30,14 +32,14 @@
   // Decoders are single-threaded, each decoder should run on |task_runner|.
   virtual void CreateAudioDecoders(
       scoped_refptr<base::SingleThreadTaskRunner> task_runner,
-      ScopedVector<AudioDecoder>* audio_decoders);
+      std::vector<std::unique_ptr<AudioDecoder>>* audio_decoders);
 
   // Creates video decoders and append them to the end of |video_decoders|.
   // Decoders are single-threaded, each decoder should run on |task_runner|.
   virtual void CreateVideoDecoders(
       scoped_refptr<base::SingleThreadTaskRunner> task_runner,
       GpuVideoAcceleratorFactories* gpu_factories,
-      ScopedVector<VideoDecoder>* video_decoders);
+      std::vector<std::unique_ptr<VideoDecoder>>* video_decoders);
 
  private:
   DISALLOW_COPY_AND_ASSIGN(DecoderFactory);
diff --git a/media/blink/webmediaplayer_impl.cc b/media/blink/webmediaplayer_impl.cc
index 51517e1..3d11799 100644
--- a/media/blink/webmediaplayer_impl.cc
+++ b/media/blink/webmediaplayer_impl.cc
@@ -933,10 +933,12 @@
 
 bool WebMediaPlayerImpl::CopyVideoTextureToPlatformTexture(
     gpu::gles2::GLES2Interface* gl,
+    unsigned int target,
     unsigned int texture,
     unsigned internal_format,
     unsigned format,
     unsigned type,
+    int level,
     bool premultiply_alpha,
     bool flip_y) {
   DCHECK(main_task_runner_->BelongsToCurrentThread());
@@ -955,8 +957,8 @@
   if (!context_3d_cb_.is_null())
     context_3d = context_3d_cb_.Run();
   return skcanvas_video_renderer_.CopyVideoFrameTexturesToGLTexture(
-      context_3d, gl, video_frame.get(), texture, internal_format, format, type,
-      premultiply_alpha, flip_y);
+      context_3d, gl, video_frame.get(), target, texture, internal_format,
+      format, type, level, premultiply_alpha, flip_y);
 }
 
 void WebMediaPlayerImpl::SetContentDecryptionModule(
diff --git a/media/blink/webmediaplayer_impl.h b/media/blink/webmediaplayer_impl.h
index 1829790c..c40b0b5 100644
--- a/media/blink/webmediaplayer_impl.h
+++ b/media/blink/webmediaplayer_impl.h
@@ -172,10 +172,12 @@
   size_t VideoDecodedByteCount() const override;
 
   bool CopyVideoTextureToPlatformTexture(gpu::gles2::GLES2Interface* gl,
+                                         unsigned int target,
                                          unsigned int texture,
                                          unsigned internal_format,
                                          unsigned format,
                                          unsigned type,
+                                         int level,
                                          bool premultiply_alpha,
                                          bool flip_y) override;
 
diff --git a/media/filters/audio_decoder_selector_unittest.cc b/media/filters/audio_decoder_selector_unittest.cc
index b38957d..5746df2 100644
--- a/media/filters/audio_decoder_selector_unittest.cc
+++ b/media/filters/audio_decoder_selector_unittest.cc
@@ -4,10 +4,10 @@
 
 #include <stddef.h>
 #include <utility>
-#include <vector>
 
 #include "base/bind.h"
 #include "base/macros.h"
+#include "base/memory/ptr_util.h"
 #include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
 #include "build/build_config.h"
@@ -60,8 +60,8 @@
             new StrictMock<MockDemuxerStream>(DemuxerStream::AUDIO)),
         decoder_1_(new StrictMock<MockAudioDecoder>(kDecoder1)),
         decoder_2_(new StrictMock<MockAudioDecoder>(kDecoder2)) {
-    all_decoders_.push_back(decoder_1_);
-    all_decoders_.push_back(decoder_2_);
+    all_decoders_.push_back(base::WrapUnique(decoder_1_));
+    all_decoders_.push_back(base::WrapUnique(decoder_2_));
     // |cdm_context_| and |decryptor_| are conditionally created in
     // InitializeDecoderSelector().
   }
@@ -91,7 +91,7 @@
     demuxer_stream_->set_audio_decoder_config(encrypted_audio_config);
   }
 
-  ScopedVector<AudioDecoder> CreateVideoDecodersForTest() {
+  std::vector<std::unique_ptr<AudioDecoder>> CreateAudioDecodersForTest() {
     return std::move(all_decoders_);
   }
 
@@ -119,7 +119,7 @@
 
     decoder_selector_.reset(new AudioDecoderSelector(
         message_loop_.task_runner(),
-        base::Bind(&AudioDecoderSelectorTest::CreateVideoDecodersForTest,
+        base::Bind(&AudioDecoderSelectorTest::CreateAudioDecodersForTest,
                    base::Unretained(this)),
         &media_log_));
   }
@@ -172,7 +172,7 @@
 
   StrictMock<MockAudioDecoder>* decoder_1_;
   StrictMock<MockAudioDecoder>* decoder_2_;
-  ScopedVector<AudioDecoder> all_decoders_;
+  std::vector<std::unique_ptr<AudioDecoder>> all_decoders_;
   std::unique_ptr<AudioDecoder> selected_decoder_;
 
   base::MessageLoop message_loop_;
diff --git a/media/filters/decoder_selector.cc b/media/filters/decoder_selector.cc
index c520eb88..23e10e52 100644
--- a/media/filters/decoder_selector.cc
+++ b/media/filters/decoder_selector.cc
@@ -202,8 +202,8 @@
 
   // Select the next non-blacklisted decoder.
   while (!decoders_.empty()) {
-    std::unique_ptr<Decoder> decoder(decoders_.front());
-    decoders_.weak_erase(decoders_.begin());
+    std::unique_ptr<Decoder> decoder(std::move(decoders_.front()));
+    decoders_.erase(decoders_.begin());
     // When |decrypted_stream_| is selected, the |config_| has changed so ignore
     // the blacklist.
     if (decrypted_stream_ ||
diff --git a/media/filters/decoder_selector.h b/media/filters/decoder_selector.h
index 0a30989..7482c3ff 100644
--- a/media/filters/decoder_selector.h
+++ b/media/filters/decoder_selector.h
@@ -6,11 +6,11 @@
 #define MEDIA_FILTERS_DECODER_SELECTOR_H_
 
 #include <memory>
+#include <vector>
 
 #include "base/callback.h"
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
-#include "base/memory/scoped_vector.h"
 #include "base/memory/weak_ptr.h"
 #include "build/build_config.h"
 #include "media/base/demuxer_stream.h"
@@ -42,7 +42,8 @@
   // Callback to create a list of decoders to select from.
   // TODO(xhwang): Use a DecoderFactory to create decoders one by one as needed,
   // instead of creating a list of decoders all at once.
-  using CreateDecodersCB = base::RepeatingCallback<ScopedVector<Decoder>()>;
+  using CreateDecodersCB =
+      base::RepeatingCallback<std::vector<std::unique_ptr<Decoder>>()>;
 
   // Indicates completion of Decoder selection.
   // - First parameter: The initialized Decoder. If it's set to NULL, then
@@ -116,7 +117,7 @@
   typename Decoder::OutputCB output_cb_;
   base::Closure waiting_for_decryption_key_cb_;
 
-  ScopedVector<Decoder> decoders_;
+  std::vector<std::unique_ptr<Decoder>> decoders_;
 
   std::unique_ptr<Decoder> decoder_;
   std::unique_ptr<DecryptingDemuxerStream> decrypted_stream_;
diff --git a/media/filters/decoder_stream.h b/media/filters/decoder_stream.h
index 380eb114..bfbde1d 100644
--- a/media/filters/decoder_stream.h
+++ b/media/filters/decoder_stream.h
@@ -8,11 +8,11 @@
 #include <deque>
 #include <list>
 #include <memory>
+#include <vector>
 
 #include "base/callback.h"
 #include "base/compiler_specific.h"
 #include "base/memory/ref_counted.h"
-#include "base/memory/scoped_vector.h"
 #include "base/memory/weak_ptr.h"
 #include "media/base/audio_decoder.h"
 #include "media/base/audio_timestamp_helper.h"
@@ -51,7 +51,8 @@
   };
 
   // Callback to create a list of decoders.
-  using CreateDecodersCB = base::RepeatingCallback<ScopedVector<Decoder>()>;
+  using CreateDecodersCB =
+      base::RepeatingCallback<std::vector<std::unique_ptr<Decoder>>()>;
 
   // Indicates completion of a DecoderStream initialization.
   using InitCB = base::Callback<void(bool success)>;
diff --git a/media/filters/gpu_video_decoder.h b/media/filters/gpu_video_decoder.h
index 8b001c7..c2a5c68a 100644
--- a/media/filters/gpu_video_decoder.h
+++ b/media/filters/gpu_video_decoder.h
@@ -49,6 +49,7 @@
   GpuVideoDecoder(GpuVideoAcceleratorFactories* factories,
                   const RequestSurfaceCB& request_surface_cb,
                   MediaLog* media_log);
+  ~GpuVideoDecoder() override;
 
   // VideoDecoder implementation.
   std::string GetDisplayName() const override;
@@ -80,9 +81,6 @@
 
   static const char kDecoderName[];
 
- protected:
-  ~GpuVideoDecoder() override;
-
  private:
   enum State {
     kNormal,
diff --git a/media/filters/video_decoder_selector_unittest.cc b/media/filters/video_decoder_selector_unittest.cc
index 5b00a6e..444be6a2 100644
--- a/media/filters/video_decoder_selector_unittest.cc
+++ b/media/filters/video_decoder_selector_unittest.cc
@@ -4,10 +4,10 @@
 
 #include <stddef.h>
 #include <utility>
-#include <vector>
 
 #include "base/bind.h"
 #include "base/macros.h"
+#include "base/memory/ptr_util.h"
 #include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
 #include "build/build_config.h"
@@ -58,8 +58,8 @@
             new StrictMock<MockDemuxerStream>(DemuxerStream::VIDEO)),
         decoder_1_(new StrictMock<MockVideoDecoder>(kDecoder1)),
         decoder_2_(new StrictMock<MockVideoDecoder>(kDecoder2)) {
-    all_decoders_.push_back(decoder_1_);
-    all_decoders_.push_back(decoder_2_);
+    all_decoders_.push_back(base::WrapUnique(decoder_1_));
+    all_decoders_.push_back(base::WrapUnique(decoder_2_));
     // |cdm_context_| and |decryptor_| are conditionally created in
     // InitializeDecoderSelector().
   }
@@ -84,7 +84,7 @@
         TestVideoConfig::NormalEncrypted());
   }
 
-  ScopedVector<VideoDecoder> CreateVideoDecodersForTest() {
+  std::vector<std::unique_ptr<VideoDecoder>> CreateVideoDecodersForTest() {
     return std::move(all_decoders_);
   }
 
@@ -167,7 +167,7 @@
 
   StrictMock<MockVideoDecoder>* decoder_1_;
   StrictMock<MockVideoDecoder>* decoder_2_;
-  ScopedVector<VideoDecoder> all_decoders_;
+  std::vector<std::unique_ptr<VideoDecoder>> all_decoders_;
   std::unique_ptr<VideoDecoder> selected_decoder_;
 
   base::MessageLoop message_loop_;
diff --git a/media/filters/video_frame_stream_unittest.cc b/media/filters/video_frame_stream_unittest.cc
index 2baf2347..8e68439 100644
--- a/media/filters/video_frame_stream_unittest.cc
+++ b/media/filters/video_frame_stream_unittest.cc
@@ -8,6 +8,7 @@
 #include "base/bind.h"
 #include "base/callback_helpers.h"
 #include "base/macros.h"
+#include "base/memory/ptr_util.h"
 #include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
 #include "base/strings/string_number_conversions.h"
@@ -124,7 +125,7 @@
   //   decoder_->SimulateFailureToInit(), and
   // - on decode error of the first buffer, which can be simulated by calling
   //   decoder_->SimulateError() before reading the first frame.
-  ScopedVector<VideoDecoder> CreateVideoDecodersForTest() {
+  std::vector<std::unique_ptr<VideoDecoder>> CreateVideoDecodersForTest() {
     // Previously decoders could have been destroyed on decoder reselection.
     decoders_.clear();
 
@@ -132,22 +133,22 @@
     // TODO(xhwang): We should test the case where only certain decoder
     // supports encrypted streams. Currently this is hard to test because we use
     // parameterized tests which need to pass in all combinations.
-    ScopedVector<VideoDecoder> decoders;
+    std::vector<std::unique_ptr<VideoDecoder>> decoders;
     for (int i = 0; i < 3; ++i) {
-      FakeVideoDecoder* decoder =
-          new FakeVideoDecoder(GetDecoderName(i), GetParam().decoding_delay,
-                               GetParam().parallel_decoding,
-                               base::Bind(&VideoFrameStreamTest::OnBytesDecoded,
-                                          base::Unretained(this)));
+      auto decoder = base::MakeUnique<FakeVideoDecoder>(
+          GetDecoderName(i), GetParam().decoding_delay,
+          GetParam().parallel_decoding,
+          base::Bind(&VideoFrameStreamTest::OnBytesDecoded,
+                     base::Unretained(this)));
 
       if (GetParam().is_encrypted && !GetParam().has_decryptor)
         decoder->EnableEncryptedConfigSupport();
 
-      decoders.push_back(decoder);
-
       // Keep a copy of the raw pointers so we can change the behavior of each
       // decoder.
-      decoders_.push_back(decoder);
+      decoders_.push_back(decoder.get());
+
+      decoders.push_back(std::move(decoder));
     }
 
     for (const auto& i : decoder_indices_to_fail_init_)
diff --git a/media/mojo/clients/mojo_decoder_factory.cc b/media/mojo/clients/mojo_decoder_factory.cc
index baf3857..84b930a2 100644
--- a/media/mojo/clients/mojo_decoder_factory.cc
+++ b/media/mojo/clients/mojo_decoder_factory.cc
@@ -4,6 +4,7 @@
 
 #include "media/mojo/clients/mojo_decoder_factory.h"
 
+#include "base/memory/ptr_util.h"
 #include "base/single_thread_task_runner.h"
 #include "media/mojo/clients/mojo_audio_decoder.h"
 #include "media/mojo/clients/mojo_video_decoder.h"
@@ -22,27 +23,27 @@
 
 void MojoDecoderFactory::CreateAudioDecoders(
     scoped_refptr<base::SingleThreadTaskRunner> task_runner,
-    ScopedVector<AudioDecoder>* audio_decoders) {
+    std::vector<std::unique_ptr<AudioDecoder>>* audio_decoders) {
 #if defined(ENABLE_MOJO_AUDIO_DECODER)
   mojom::AudioDecoderPtr audio_decoder_ptr;
   service_manager::GetInterface<mojom::AudioDecoder>(interface_provider_,
                                                      &audio_decoder_ptr);
 
-  audio_decoders->push_back(
-      new MojoAudioDecoder(task_runner, std::move(audio_decoder_ptr)));
+  audio_decoders->push_back(base::MakeUnique<MojoAudioDecoder>(
+      task_runner, std::move(audio_decoder_ptr)));
 #endif
 }
 
 void MojoDecoderFactory::CreateVideoDecoders(
     scoped_refptr<base::SingleThreadTaskRunner> task_runner,
     GpuVideoAcceleratorFactories* gpu_factories,
-    ScopedVector<VideoDecoder>* video_decoders) {
+    std::vector<std::unique_ptr<VideoDecoder>>* video_decoders) {
 #if defined(ENABLE_MOJO_VIDEO_DECODER)
   mojom::VideoDecoderPtr remote_decoder;
   service_manager::GetInterface<mojom::VideoDecoder>(interface_provider_,
                                                      &remote_decoder);
-  video_decoders->push_back(new MojoVideoDecoder(task_runner, gpu_factories,
-                                                 std::move(remote_decoder)));
+  video_decoders->push_back(base::MakeUnique<MojoVideoDecoder>(
+      task_runner, gpu_factories, std::move(remote_decoder)));
 #endif
 }
 
diff --git a/media/mojo/clients/mojo_decoder_factory.h b/media/mojo/clients/mojo_decoder_factory.h
index c808dbc4..7cb0101 100644
--- a/media/mojo/clients/mojo_decoder_factory.h
+++ b/media/mojo/clients/mojo_decoder_factory.h
@@ -19,12 +19,12 @@
 
   void CreateAudioDecoders(
       scoped_refptr<base::SingleThreadTaskRunner> task_runner,
-      ScopedVector<AudioDecoder>* audio_decoders) final;
+      std::vector<std::unique_ptr<AudioDecoder>>* audio_decoders) final;
 
   void CreateVideoDecoders(
       scoped_refptr<base::SingleThreadTaskRunner> task_runner,
       GpuVideoAcceleratorFactories* gpu_factories,
-      ScopedVector<VideoDecoder>* video_decoders) final;
+      std::vector<std::unique_ptr<VideoDecoder>>* video_decoders) final;
 
  private:
   service_manager::mojom::InterfaceProvider* interface_provider_;
diff --git a/media/renderers/audio_renderer_impl_unittest.cc b/media/renderers/audio_renderer_impl_unittest.cc
index 1b0e5a54..7085987 100644
--- a/media/renderers/audio_renderer_impl_unittest.cc
+++ b/media/renderers/audio_renderer_impl_unittest.cc
@@ -6,11 +6,13 @@
 
 #include <memory>
 #include <utility>
+#include <vector>
 
 #include "base/bind.h"
 #include "base/callback_helpers.h"
 #include "base/format_macros.h"
 #include "base/macros.h"
+#include "base/memory/ptr_util.h"
 #include "base/run_loop.h"
 #include "base/single_thread_task_runner.h"
 #include "base/strings/stringprintf.h"
@@ -66,8 +68,8 @@
 
 class AudioRendererImplTest : public ::testing::Test, public RendererClient {
  public:
-  ScopedVector<AudioDecoder> CreateAudioDecoderForTest() {
-    MockAudioDecoder* decoder = new MockAudioDecoder();
+  std::vector<std::unique_ptr<AudioDecoder>> CreateAudioDecoderForTest() {
+    auto decoder = base::MakeUnique<MockAudioDecoder>();
     if (!enter_pending_decoder_init_) {
       EXPECT_CALL(*decoder, Initialize(_, _, _, _))
           .WillOnce(DoAll(SaveArg<3>(&output_cb_),
@@ -80,8 +82,8 @@
         .WillRepeatedly(Invoke(this, &AudioRendererImplTest::DecodeDecoder));
     EXPECT_CALL(*decoder, Reset(_))
         .WillRepeatedly(Invoke(this, &AudioRendererImplTest::ResetDecoder));
-    ScopedVector<AudioDecoder> decoders;
-    decoders.push_back(decoder);
+    std::vector<std::unique_ptr<AudioDecoder>> decoders;
+    decoders.push_back(std::move(decoder));
     return decoders;
   }
 
diff --git a/media/renderers/default_renderer_factory.cc b/media/renderers/default_renderer_factory.cc
index 9d61092..b6a7824f 100644
--- a/media/renderers/default_renderer_factory.cc
+++ b/media/renderers/default_renderer_factory.cc
@@ -42,14 +42,15 @@
 DefaultRendererFactory::~DefaultRendererFactory() {
 }
 
-ScopedVector<AudioDecoder> DefaultRendererFactory::CreateAudioDecoders(
+std::vector<std::unique_ptr<AudioDecoder>>
+DefaultRendererFactory::CreateAudioDecoders(
     const scoped_refptr<base::SingleThreadTaskRunner>& media_task_runner) {
   // Create our audio decoders and renderer.
-  ScopedVector<AudioDecoder> audio_decoders;
+  std::vector<std::unique_ptr<AudioDecoder>> audio_decoders;
 
 #if !defined(MEDIA_DISABLE_FFMPEG)
   audio_decoders.push_back(
-      new FFmpegAudioDecoder(media_task_runner, media_log_));
+      base::MakeUnique<FFmpegAudioDecoder>(media_task_runner, media_log_));
 #endif
 
   // Use an external decoder only if we cannot otherwise decode in the
@@ -60,12 +61,13 @@
   return audio_decoders;
 }
 
-ScopedVector<VideoDecoder> DefaultRendererFactory::CreateVideoDecoders(
+std::vector<std::unique_ptr<VideoDecoder>>
+DefaultRendererFactory::CreateVideoDecoders(
     const scoped_refptr<base::SingleThreadTaskRunner>& media_task_runner,
     const RequestSurfaceCB& request_surface_cb,
     GpuVideoAcceleratorFactories* gpu_factories) {
   // Create our video decoders and renderer.
-  ScopedVector<VideoDecoder> video_decoders;
+  std::vector<std::unique_ptr<VideoDecoder>> video_decoders;
 
   // Prefer an external decoder since one will only exist if it is hardware
   // accelerated.
@@ -79,16 +81,16 @@
       decoder_factory_->CreateVideoDecoders(media_task_runner, gpu_factories,
                                             &video_decoders);
     }
-    video_decoders.push_back(
-        new GpuVideoDecoder(gpu_factories, request_surface_cb, media_log_));
+    video_decoders.push_back(base::MakeUnique<GpuVideoDecoder>(
+        gpu_factories, request_surface_cb, media_log_));
   }
 
 #if !defined(MEDIA_DISABLE_LIBVPX)
-  video_decoders.push_back(new VpxVideoDecoder());
+  video_decoders.push_back(base::MakeUnique<VpxVideoDecoder>());
 #endif
 
 #if !defined(MEDIA_DISABLE_FFMPEG) && !defined(DISABLE_FFMPEG_VIDEO_DECODERS)
-  video_decoders.push_back(new FFmpegVideoDecoder(media_log_));
+  video_decoders.push_back(base::MakeUnique<FFmpegVideoDecoder>(media_log_));
 #endif
 
   return video_decoders;
diff --git a/media/renderers/default_renderer_factory.h b/media/renderers/default_renderer_factory.h
index ba6a936..ea4ebf71 100644
--- a/media/renderers/default_renderer_factory.h
+++ b/media/renderers/default_renderer_factory.h
@@ -6,10 +6,10 @@
 #define MEDIA_RENDERERS_DEFAULT_RENDERER_FACTORY_H_
 
 #include <memory>
+#include <vector>
 
 #include "base/callback.h"
 #include "base/macros.h"
-#include "base/memory/scoped_vector.h"
 #include "media/base/media_export.h"
 #include "media/base/renderer_factory.h"
 
@@ -24,9 +24,9 @@
 class VideoRendererSink;
 
 using CreateAudioDecodersCB =
-    base::RepeatingCallback<ScopedVector<AudioDecoder>()>;
+    base::RepeatingCallback<std::vector<std::unique_ptr<AudioDecoder>>()>;
 using CreateVideoDecodersCB =
-    base::RepeatingCallback<ScopedVector<VideoDecoder>()>;
+    base::RepeatingCallback<std::vector<std::unique_ptr<VideoDecoder>>()>;
 
 // The default factory class for creating RendererImpl.
 class MEDIA_EXPORT DefaultRendererFactory : public RendererFactory {
@@ -46,9 +46,9 @@
       const RequestSurfaceCB& request_surface_cb) final;
 
  private:
-  ScopedVector<AudioDecoder> CreateAudioDecoders(
+  std::vector<std::unique_ptr<AudioDecoder>> CreateAudioDecoders(
       const scoped_refptr<base::SingleThreadTaskRunner>& media_task_runner);
-  ScopedVector<VideoDecoder> CreateVideoDecoders(
+  std::vector<std::unique_ptr<VideoDecoder>> CreateVideoDecoders(
       const scoped_refptr<base::SingleThreadTaskRunner>& media_task_runner,
       const RequestSurfaceCB& request_surface_cb,
       GpuVideoAcceleratorFactories* gpu_factories);
diff --git a/media/renderers/skcanvas_video_renderer.cc b/media/renderers/skcanvas_video_renderer.cc
index f8e8faa..395f6d6 100644
--- a/media/renderers/skcanvas_video_renderer.cc
+++ b/media/renderers/skcanvas_video_renderer.cc
@@ -204,7 +204,8 @@
     SkCanvasVideoRenderer::CopyVideoFrameSingleTextureToGLTexture(
         gl, video_frame,
         SkCanvasVideoRenderer::SingleFrameForVideoElementOrCanvas,
-        source_texture, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, true, false);
+        GL_TEXTURE_2D, source_texture, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, 0,
+        true, false);
     context_3d.gr_context->resetContext(kTextureBinding_GrGLBackendState);
   } else {
     gl->WaitSyncTokenCHROMIUM(mailbox_holder.sync_token.GetConstData());
@@ -805,10 +806,12 @@
     gpu::gles2::GLES2Interface* gl,
     VideoFrame* video_frame,
     SingleFrameCopyMode copy_mode,
+    unsigned int target,
     unsigned int texture,
     unsigned int internal_format,
     unsigned int format,
     unsigned int type,
+    int level,
     bool premultiply_alpha,
     bool flip_y) {
   DCHECK(video_frame);
@@ -834,7 +837,7 @@
   if (copy_mode == SingleFrameForVideoElementOrCanvas ||
       !VideoTextureNeedsClipping(video_frame)) {
     // No need to clip the source video texture.
-    gl->CopyTextureCHROMIUM(source_texture, 0, GL_TEXTURE_2D, texture, 0,
+    gl->CopyTextureCHROMIUM(source_texture, 0, target, texture, level,
                             internal_format, type, flip_y, premultiply_alpha,
                             false);
   } else {
@@ -852,12 +855,12 @@
     DCHECK_LE(dest_rect.width(), video_frame->coded_size().width());
     DCHECK_LE(dest_rect.height(), video_frame->coded_size().height());
 #endif
-    gl->TexImage2D(GL_TEXTURE_2D, 0, internal_format, dest_rect.width(),
+    gl->TexImage2D(target, level, internal_format, dest_rect.width(),
                    dest_rect.height(), 0, format, type, nullptr);
-    gl->CopySubTextureCHROMIUM(source_texture, 0, GL_TEXTURE_2D, texture, 0, 0,
-                               0, dest_rect.x(), dest_rect.y(),
-                               dest_rect.width(), dest_rect.height(), flip_y,
-                               premultiply_alpha, false);
+    gl->CopySubTextureCHROMIUM(source_texture, 0, target, texture, level, 0, 0,
+                               dest_rect.x(), dest_rect.y(), dest_rect.width(),
+                               dest_rect.height(), flip_y, premultiply_alpha,
+                               false);
   }
 
   gl->DeleteTextures(1, &source_texture);
@@ -871,10 +874,12 @@
     const Context3D& context_3d,
     gpu::gles2::GLES2Interface* destination_gl,
     const scoped_refptr<VideoFrame>& video_frame,
+    unsigned int target,
     unsigned int texture,
     unsigned int internal_format,
     unsigned int format,
     unsigned int type,
+    int level,
     bool premultiply_alpha,
     bool flip_y) {
   DCHECK(thread_checker_.CalledOnValidThread());
@@ -927,17 +932,17 @@
       DCHECK_LE(dest_rect.width(), video_frame->coded_size().width());
       DCHECK_LE(dest_rect.height(), video_frame->coded_size().height());
 #endif
-      destination_gl->TexImage2D(GL_TEXTURE_2D, 0, internal_format,
+      destination_gl->TexImage2D(target, level, internal_format,
                                  dest_rect.width(), dest_rect.height(), 0,
                                  format, type, nullptr);
       destination_gl->CopySubTextureCHROMIUM(
-          intermediate_texture, 0, GL_TEXTURE_2D, texture, 0, 0, 0,
-          dest_rect.x(), dest_rect.y(), dest_rect.width(), dest_rect.height(),
-          flip_y, premultiply_alpha, false);
+          intermediate_texture, 0, target, texture, level, 0, 0, dest_rect.x(),
+          dest_rect.y(), dest_rect.width(), dest_rect.height(), flip_y,
+          premultiply_alpha, false);
     } else {
-      destination_gl->CopyTextureCHROMIUM(
-          intermediate_texture, 0, GL_TEXTURE_2D, texture, 0, internal_format,
-          type, flip_y, premultiply_alpha, false);
+      destination_gl->CopyTextureCHROMIUM(intermediate_texture, 0, target,
+                                          texture, level, internal_format, type,
+                                          flip_y, premultiply_alpha, false);
     }
 
     destination_gl->DeleteTextures(1, &intermediate_texture);
@@ -955,8 +960,8 @@
     video_frame->UpdateReleaseSyncToken(&client);
   } else {
     CopyVideoFrameSingleTextureToGLTexture(
-        destination_gl, video_frame.get(), SingleFrameForWebGL, texture,
-        internal_format, format, type, premultiply_alpha, flip_y);
+        destination_gl, video_frame.get(), SingleFrameForWebGL, target, texture,
+        internal_format, format, type, level, premultiply_alpha, flip_y);
   }
 
   return true;
diff --git a/media/renderers/skcanvas_video_renderer.h b/media/renderers/skcanvas_video_renderer.h
index ae76c1d..a643778 100644
--- a/media/renderers/skcanvas_video_renderer.h
+++ b/media/renderers/skcanvas_video_renderer.h
@@ -83,10 +83,12 @@
       gpu::gles2::GLES2Interface* gl,
       VideoFrame* video_frame,
       SingleFrameCopyMode copy_mode,
+      unsigned int target,
       unsigned int texture,
       unsigned int internal_format,
       unsigned int format,
       unsigned int type,
+      int level,
       bool premultiply_alpha,
       bool flip_y);
 
@@ -100,10 +102,12 @@
       const Context3D& context_3d,
       gpu::gles2::GLES2Interface* destination_gl,
       const scoped_refptr<VideoFrame>& video_frame,
+      unsigned int target,
       unsigned int texture,
       unsigned int internal_format,
       unsigned int format,
       unsigned int type,
+      int level,
       bool premultiply_alpha,
       bool flip_y);
 
diff --git a/media/renderers/video_renderer_impl.h b/media/renderers/video_renderer_impl.h
index d33b0ec..b4d7b42 100644
--- a/media/renderers/video_renderer_impl.h
+++ b/media/renderers/video_renderer_impl.h
@@ -13,7 +13,6 @@
 
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
-#include "base/memory/scoped_vector.h"
 #include "base/memory/weak_ptr.h"
 #include "base/synchronization/condition_variable.h"
 #include "base/synchronization/lock.h"
diff --git a/media/renderers/video_renderer_impl_unittest.cc b/media/renderers/video_renderer_impl_unittest.cc
index 62f01ea..ebb9043 100644
--- a/media/renderers/video_renderer_impl_unittest.cc
+++ b/media/renderers/video_renderer_impl_unittest.cc
@@ -53,10 +53,10 @@
 
 class VideoRendererImplTest : public testing::Test {
  public:
-  ScopedVector<VideoDecoder> CreateVideoDecodersForTest() {
+  std::vector<std::unique_ptr<VideoDecoder>> CreateVideoDecodersForTest() {
     decoder_ = new NiceMock<MockVideoDecoder>();
-    ScopedVector<VideoDecoder> decoders;
-    decoders.push_back(decoder_);
+    std::vector<std::unique_ptr<VideoDecoder>> decoders;
+    decoders.push_back(base::WrapUnique(decoder_));
     ON_CALL(*decoder_, Initialize(_, _, _, _, _))
         .WillByDefault(DoAll(SaveArg<4>(&output_cb_),
                              RunCallback<3>(expect_init_success_)));
diff --git a/media/test/pipeline_integration_test.cc b/media/test/pipeline_integration_test.cc
index cd53510..331b9d3 100644
--- a/media/test/pipeline_integration_test.cc
+++ b/media/test/pipeline_integration_test.cc
@@ -1369,9 +1369,9 @@
   ASSERT_TRUE(WaitUntilOnEnded());
 }
 
-ScopedVector<VideoDecoder> CreateFailingVideoDecoder() {
-  ScopedVector<VideoDecoder> failing_video_decoder;
-  failing_video_decoder.push_back(new FailingVideoDecoder());
+std::vector<std::unique_ptr<VideoDecoder>> CreateFailingVideoDecoder() {
+  std::vector<std::unique_ptr<VideoDecoder>> failing_video_decoder;
+  failing_video_decoder.push_back(base::MakeUnique<FailingVideoDecoder>());
   return failing_video_decoder;
 }
 
diff --git a/media/test/pipeline_integration_test_base.cc b/media/test/pipeline_integration_test_base.cc
index c0b746d..1629a0b 100644
--- a/media/test/pipeline_integration_test_base.cc
+++ b/media/test/pipeline_integration_test_base.cc
@@ -9,7 +9,6 @@
 #include "base/bind.h"
 #include "base/memory/ptr_util.h"
 #include "base/memory/ref_counted.h"
-#include "base/memory/scoped_vector.h"
 #include "base/run_loop.h"
 #include "base/single_thread_task_runner.h"
 #include "media/base/media_log.h"
@@ -41,10 +40,10 @@
 
 namespace media {
 
-static ScopedVector<VideoDecoder> CreateVideoDecodersForTest(
+static std::vector<std::unique_ptr<VideoDecoder>> CreateVideoDecodersForTest(
     MediaLog* media_log,
     CreateVideoDecodersCB prepend_video_decoders_cb) {
-  ScopedVector<VideoDecoder> video_decoders;
+  std::vector<std::unique_ptr<VideoDecoder>> video_decoders;
 
   if (!prepend_video_decoders_cb.is_null()) {
     video_decoders = prepend_video_decoders_cb.Run();
@@ -52,22 +51,22 @@
   }
 
 #if !defined(MEDIA_DISABLE_LIBVPX)
-  video_decoders.push_back(new VpxVideoDecoder());
+  video_decoders.push_back(base::MakeUnique<VpxVideoDecoder>());
 #endif  // !defined(MEDIA_DISABLE_LIBVPX)
 
 // Android does not have an ffmpeg video decoder.
 #if !defined(MEDIA_DISABLE_FFMPEG) && !defined(OS_ANDROID) && \
     !defined(DISABLE_FFMPEG_VIDEO_DECODERS)
-  video_decoders.push_back(new FFmpegVideoDecoder(media_log));
+  video_decoders.push_back(base::MakeUnique<FFmpegVideoDecoder>(media_log));
 #endif
   return video_decoders;
 }
 
-static ScopedVector<AudioDecoder> CreateAudioDecodersForTest(
+static std::vector<std::unique_ptr<AudioDecoder>> CreateAudioDecodersForTest(
     MediaLog* media_log,
     const scoped_refptr<base::SingleThreadTaskRunner>& media_task_runner,
     CreateAudioDecodersCB prepend_audio_decoders_cb) {
-  ScopedVector<AudioDecoder> audio_decoders;
+  std::vector<std::unique_ptr<AudioDecoder>> audio_decoders;
 
   if (!prepend_audio_decoders_cb.is_null()) {
     audio_decoders = prepend_audio_decoders_cb.Run();
@@ -76,7 +75,7 @@
 
 #if !defined(MEDIA_DISABLE_FFMPEG)
   audio_decoders.push_back(
-      new FFmpegAudioDecoder(media_task_runner, media_log));
+      base::MakeUnique<FFmpegAudioDecoder>(media_task_runner, media_log));
 #endif
   return audio_decoders;
 }
diff --git a/net/BUILD.gn b/net/BUILD.gn
index 33c06a17..231e6e8f 100644
--- a/net/BUILD.gn
+++ b/net/BUILD.gn
@@ -1228,6 +1228,7 @@
       "quic/core/frames/quic_stream_frame.h",
       "quic/core/frames/quic_window_update_frame.cc",
       "quic/core/frames/quic_window_update_frame.h",
+      "quic/core/packet_number_indexed_queue.h",
       "quic/core/quic_ack_listener_interface.cc",
       "quic/core/quic_ack_listener_interface.h",
       "quic/core/quic_alarm.cc",
@@ -4611,6 +4612,7 @@
     "quic/core/crypto/quic_random_test.cc",
     "quic/core/crypto/strike_register_test.cc",
     "quic/core/frames/quic_frames_test.cc",
+    "quic/core/packet_number_indexed_queue_test.cc",
     "quic/core/quic_alarm_test.cc",
     "quic/core/quic_arena_scoped_ptr_test.cc",
     "quic/core/quic_bandwidth_test.cc",
diff --git a/net/quic/chromium/quic_chromium_client_session.cc b/net/quic/chromium/quic_chromium_client_session.cc
index 045ae4d3..3f3843e5d 100644
--- a/net/quic/chromium/quic_chromium_client_session.cc
+++ b/net/quic/chromium/quic_chromium_client_session.cc
@@ -1586,12 +1586,11 @@
                                 ConnectionCloseBehavior::SILENT_CLOSE);
 }
 
-bool QuicChromiumClientSession::OnPacket(const QuicReceivedPacket& packet,
-                                         const IPEndPoint& local_address,
-                                         const IPEndPoint& peer_address) {
-  ProcessUdpPacket(QuicSocketAddress(QuicSocketAddressImpl(local_address)),
-                   QuicSocketAddress(QuicSocketAddressImpl(peer_address)),
-                   packet);
+bool QuicChromiumClientSession::OnPacket(
+    const QuicReceivedPacket& packet,
+    const QuicSocketAddress& local_address,
+    const QuicSocketAddress& peer_address) {
+  ProcessUdpPacket(local_address, peer_address, packet);
   if (!connection()->connected()) {
     NotifyFactoryOfSessionClosedLater();
     return false;
diff --git a/net/quic/chromium/quic_chromium_client_session.h b/net/quic/chromium/quic_chromium_client_session.h
index 7c072630..306224b7 100644
--- a/net/quic/chromium/quic_chromium_client_session.h
+++ b/net/quic/chromium/quic_chromium_client_session.h
@@ -341,8 +341,8 @@
   // QuicChromiumPacketReader::Visitor methods:
   void OnReadError(int result, const DatagramClientSocket* socket) override;
   bool OnPacket(const QuicReceivedPacket& packet,
-                const IPEndPoint& local_address,
-                const IPEndPoint& peer_address) override;
+                const QuicSocketAddress& local_address,
+                const QuicSocketAddress& peer_address) override;
 
   // MultiplexedSession methods:
   bool GetRemoteEndpoint(IPEndPoint* endpoint) override;
diff --git a/net/quic/chromium/quic_chromium_packet_reader.cc b/net/quic/chromium/quic_chromium_packet_reader.cc
index c151a0eb..97e649e 100644
--- a/net/quic/chromium/quic_chromium_packet_reader.cc
+++ b/net/quic/chromium/quic_chromium_packet_reader.cc
@@ -86,7 +86,9 @@
   IPEndPoint peer_address;
   socket_->GetLocalAddress(&local_address);
   socket_->GetPeerAddress(&peer_address);
-  if (!visitor_->OnPacket(packet, local_address, peer_address))
+  if (!visitor_->OnPacket(
+          packet, QuicSocketAddress(QuicSocketAddressImpl(local_address)),
+          QuicSocketAddress(QuicSocketAddressImpl(peer_address))))
     return;
 
   StartReading();
diff --git a/net/quic/chromium/quic_chromium_packet_reader.h b/net/quic/chromium/quic_chromium_packet_reader.h
index 8ab492a..3918fc0 100644
--- a/net/quic/chromium/quic_chromium_packet_reader.h
+++ b/net/quic/chromium/quic_chromium_packet_reader.h
@@ -33,8 +33,8 @@
     virtual void OnReadError(int result,
                              const DatagramClientSocket* socket) = 0;
     virtual bool OnPacket(const QuicReceivedPacket& packet,
-                          const IPEndPoint& local_address,
-                          const IPEndPoint& peer_address) = 0;
+                          const QuicSocketAddress& local_address,
+                          const QuicSocketAddress& peer_address) = 0;
   };
 
   QuicChromiumPacketReader(DatagramClientSocket* socket,
diff --git a/net/quic/core/packet_number_indexed_queue.h b/net/quic/core/packet_number_indexed_queue.h
new file mode 100644
index 0000000..677b971
--- /dev/null
+++ b/net/quic/core/packet_number_indexed_queue.h
@@ -0,0 +1,192 @@
+// Copyright (c) 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef NET_QUIC_CORE_PACKET_NUMBER_INDEXED_QUEUE_H_
+#define NET_QUIC_CORE_PACKET_NUMBER_INDEXED_QUEUE_H_
+
+#include <deque>
+
+#include "base/logging.h"
+#include "net/quic/core/quic_types.h"
+
+namespace net {
+
+// PacketNumberIndexedQueue is a queue of mostly continuous numbered entries
+// which supports the following operations:
+// - adding elements to the end of the queue, or at some point past the end
+// - removing elements in any order
+// - retrieving elements
+// If all elements are inserted in order, all of the operations above are
+// amortized O(1) time.
+//
+// Internally, the data structure is a deque where each element is marked as
+// present or not.  The deque starts at the lowest present index.  Whenever an
+// element is removed, it's marked as not present, and the front of the deque is
+// cleared of elements that are not present.
+//
+// The tail of the queue is not cleared due to the assumption of entries being
+// inserted in order, though removing all elements of the queue will return it
+// to its initial state.
+//
+// Note that this data structure is inherently hazardous, since an addition of
+// just two entries will cause it to consume all of the memory available.
+// Because of that, it is not a general-purpose container and should not be used
+// as one.
+template <typename T>
+class PacketNumberIndexedQueue {
+ public:
+  PacketNumberIndexedQueue()
+      : number_of_present_entries_(0), first_packet_(0) {}
+
+  // Retrieve the entry associated with the packet number.  Returns the pointer
+  // to the entry in case of success, or nullptr if the entry does not exist.
+  T* GetEntry(QuicPacketNumber packet_number);
+
+  // Inserts data associated |packet_number| into (or past) the end of the
+  // queue, filling up the missing intermediate entries as necessary.  Returns
+  // true if the element has been inserted successfully, false if it was already
+  // in the queue or inserted out of order.
+  template <typename... Args>
+  bool Emplace(QuicPacketNumber packet_number, Args&&... args);
+
+  // Removes data associated with |packet_number| and frees the slots in the
+  // queue as necessary.
+  bool Remove(QuicPacketNumber packet_number);
+
+  bool IsEmpty() const { return number_of_present_entries_ == 0; }
+
+  // Returns the number of entries in the queue.
+  size_t number_of_present_entries() const {
+    return number_of_present_entries_;
+  }
+
+  // Returns the number of entries allocated in the underlying deque.  This is
+  // proportional to the memory usage of the queue.
+  size_t entry_slots_used() const { return entries_.size(); }
+
+  // Packet number of the first entry in the queue.  Zero if the queue is empty.
+  size_t first_packet() const { return first_packet_; }
+
+  // Packet number of the last entry ever inserted in the queue.  Note that the
+  // entry in question may have already been removed.  Zero if the queue is
+  // empty.
+  size_t last_packet() const {
+    if (IsEmpty()) {
+      return 0;
+    }
+    return first_packet_ + entries_.size() - 1;
+  }
+
+ private:
+  // Wrapper around T used to mark whether the entry is actually in the map.
+  struct EntryWrapper {
+    T data;
+    bool present;
+
+    EntryWrapper() : data(), present(false) {}
+
+    template <typename... Args>
+    explicit EntryWrapper(Args&&... args)
+        : data(std::forward<Args>(args)...), present(true) {}
+  };
+
+  // Cleans up unused slots in the front after removing an element.
+  void Cleanup();
+
+  EntryWrapper* GetEntryWrapper(QuicPacketNumber offset);
+
+  std::deque<EntryWrapper> entries_;
+  size_t number_of_present_entries_;
+  QuicPacketNumber first_packet_;
+};
+
+template <typename T>
+T* PacketNumberIndexedQueue<T>::GetEntry(QuicPacketNumber packet_number) {
+  EntryWrapper* entry = GetEntryWrapper(packet_number);
+  if (entry == nullptr) {
+    return nullptr;
+  }
+  return &entry->data;
+}
+
+template <typename T>
+template <typename... Args>
+bool PacketNumberIndexedQueue<T>::Emplace(QuicPacketNumber packet_number,
+                                          Args&&... args) {
+  if (IsEmpty()) {
+    DCHECK(entries_.empty());
+    DCHECK_EQ(0u, first_packet_);
+
+    entries_.emplace_back(std::forward<Args>(args)...);
+    number_of_present_entries_ = 1;
+    first_packet_ = packet_number;
+    return true;
+  }
+
+  // Do not allow insertion out-of-order.
+  if (packet_number <= last_packet()) {
+    return false;
+  }
+
+  // Handle potentially missing elements.
+  size_t offset = packet_number - first_packet_;
+  if (offset > entries_.size()) {
+    entries_.resize(offset);
+  }
+
+  number_of_present_entries_++;
+  entries_.emplace_back(std::forward<Args>(args)...);
+  DCHECK_EQ(packet_number, last_packet());
+  return true;
+}
+
+template <typename T>
+bool PacketNumberIndexedQueue<T>::Remove(QuicPacketNumber packet_number) {
+  EntryWrapper* entry = GetEntryWrapper(packet_number);
+  if (entry == nullptr) {
+    return false;
+  }
+  entry->present = false;
+  number_of_present_entries_--;
+
+  if (packet_number == first_packet()) {
+    Cleanup();
+  }
+  return true;
+}
+
+template <typename T>
+void PacketNumberIndexedQueue<T>::Cleanup() {
+  while (!entries_.empty() && !entries_.front().present) {
+    entries_.pop_front();
+    first_packet_++;
+  }
+  if (entries_.empty()) {
+    first_packet_ = 0;
+  }
+}
+
+template <typename T>
+auto PacketNumberIndexedQueue<T>::GetEntryWrapper(QuicPacketNumber offset)
+    -> EntryWrapper* {
+  if (offset < first_packet_) {
+    return nullptr;
+  }
+
+  offset -= first_packet_;
+  if (offset >= entries_.size()) {
+    return nullptr;
+  }
+
+  EntryWrapper* entry = &entries_[offset];
+  if (!entry->present) {
+    return nullptr;
+  }
+
+  return entry;
+}
+
+}  // namespace net
+
+#endif  // NET_QUIC_CORE_PACKET_NUMBER_INDEXED_QUEUE_H_
diff --git a/net/quic/core/packet_number_indexed_queue_test.cc b/net/quic/core/packet_number_indexed_queue_test.cc
new file mode 100644
index 0000000..2fb30b7
--- /dev/null
+++ b/net/quic/core/packet_number_indexed_queue_test.cc
@@ -0,0 +1,173 @@
+// Copyright (c) 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/quic/core/packet_number_indexed_queue.h"
+
+#include <limits>
+#include <map>
+#include <string>
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+using std::string;
+
+namespace net {
+namespace {
+
+class PacketNumberIndexedQueueTest : public ::testing::Test {
+ public:
+  PacketNumberIndexedQueueTest() {}
+
+ protected:
+  PacketNumberIndexedQueue<string> queue_;
+};
+
+TEST_F(PacketNumberIndexedQueueTest, InitialState) {
+  EXPECT_TRUE(queue_.IsEmpty());
+  EXPECT_EQ(0u, queue_.first_packet());
+  EXPECT_EQ(0u, queue_.last_packet());
+  EXPECT_EQ(0u, queue_.number_of_present_entries());
+  EXPECT_EQ(0u, queue_.entry_slots_used());
+}
+
+TEST_F(PacketNumberIndexedQueueTest, InsertingContinuousElements) {
+  ASSERT_TRUE(queue_.Emplace(1001, "one"));
+  EXPECT_EQ("one", *queue_.GetEntry(1001));
+
+  ASSERT_TRUE(queue_.Emplace(1002, "two"));
+  EXPECT_EQ("two", *queue_.GetEntry(1002));
+
+  EXPECT_FALSE(queue_.IsEmpty());
+  EXPECT_EQ(1001u, queue_.first_packet());
+  EXPECT_EQ(1002u, queue_.last_packet());
+  EXPECT_EQ(2u, queue_.number_of_present_entries());
+  EXPECT_EQ(2u, queue_.entry_slots_used());
+}
+
+TEST_F(PacketNumberIndexedQueueTest, InsertingOutOfOrder) {
+  queue_.Emplace(1001, "one");
+
+  ASSERT_TRUE(queue_.Emplace(1003, "three"));
+  EXPECT_EQ(nullptr, queue_.GetEntry(1002));
+  EXPECT_EQ("three", *queue_.GetEntry(1003));
+
+  EXPECT_EQ(1001u, queue_.first_packet());
+  EXPECT_EQ(1003u, queue_.last_packet());
+  EXPECT_EQ(2u, queue_.number_of_present_entries());
+  EXPECT_EQ(3u, queue_.entry_slots_used());
+
+  ASSERT_FALSE(queue_.Emplace(1002, "two"));
+}
+
+TEST_F(PacketNumberIndexedQueueTest, InsertingIntoPast) {
+  queue_.Emplace(1001, "one");
+  EXPECT_FALSE(queue_.Emplace(1000, "zero"));
+}
+
+TEST_F(PacketNumberIndexedQueueTest, InsertingDuplicate) {
+  queue_.Emplace(1001, "one");
+  EXPECT_FALSE(queue_.Emplace(1001, "one"));
+}
+
+TEST_F(PacketNumberIndexedQueueTest, RemoveInTheMiddle) {
+  queue_.Emplace(1001, "one");
+  queue_.Emplace(1002, "two");
+  queue_.Emplace(1003, "three");
+
+  ASSERT_TRUE(queue_.Remove(1002));
+  EXPECT_EQ(nullptr, queue_.GetEntry(1002));
+
+  EXPECT_EQ(1001u, queue_.first_packet());
+  EXPECT_EQ(1003u, queue_.last_packet());
+  EXPECT_EQ(2u, queue_.number_of_present_entries());
+  EXPECT_EQ(3u, queue_.entry_slots_used());
+
+  EXPECT_FALSE(queue_.Emplace(1002, "two"));
+  EXPECT_TRUE(queue_.Emplace(1004, "four"));
+}
+
+TEST_F(PacketNumberIndexedQueueTest, RemoveAtImmediateEdges) {
+  queue_.Emplace(1001, "one");
+  queue_.Emplace(1002, "two");
+  queue_.Emplace(1003, "three");
+  ASSERT_TRUE(queue_.Remove(1001));
+  EXPECT_EQ(nullptr, queue_.GetEntry(1001));
+  ASSERT_TRUE(queue_.Remove(1003));
+  EXPECT_EQ(nullptr, queue_.GetEntry(1003));
+
+  EXPECT_EQ(1002u, queue_.first_packet());
+  EXPECT_EQ(1003u, queue_.last_packet());
+  EXPECT_EQ(1u, queue_.number_of_present_entries());
+  EXPECT_EQ(2u, queue_.entry_slots_used());
+
+  EXPECT_TRUE(queue_.Emplace(1004, "four"));
+}
+
+TEST_F(PacketNumberIndexedQueueTest, RemoveAtDistantFront) {
+  queue_.Emplace(1001, "one");
+  queue_.Emplace(1002, "one (kinda)");
+  queue_.Emplace(2001, "two");
+
+  EXPECT_EQ(1001u, queue_.first_packet());
+  EXPECT_EQ(2001u, queue_.last_packet());
+  EXPECT_EQ(3u, queue_.number_of_present_entries());
+  EXPECT_EQ(1001u, queue_.entry_slots_used());
+
+  ASSERT_TRUE(queue_.Remove(1002));
+  EXPECT_EQ(1001u, queue_.first_packet());
+  EXPECT_EQ(2001u, queue_.last_packet());
+  EXPECT_EQ(2u, queue_.number_of_present_entries());
+  EXPECT_EQ(1001u, queue_.entry_slots_used());
+
+  ASSERT_TRUE(queue_.Remove(1001));
+  EXPECT_EQ(2001u, queue_.first_packet());
+  EXPECT_EQ(2001u, queue_.last_packet());
+  EXPECT_EQ(1u, queue_.number_of_present_entries());
+  EXPECT_EQ(1u, queue_.entry_slots_used());
+}
+
+TEST_F(PacketNumberIndexedQueueTest, RemoveAtDistantBack) {
+  queue_.Emplace(1001, "one");
+  queue_.Emplace(2001, "two");
+
+  EXPECT_EQ(1001u, queue_.first_packet());
+  EXPECT_EQ(2001u, queue_.last_packet());
+
+  ASSERT_TRUE(queue_.Remove(2001));
+  EXPECT_EQ(1001u, queue_.first_packet());
+  EXPECT_EQ(2001u, queue_.last_packet());
+}
+
+TEST_F(PacketNumberIndexedQueueTest, ClearAndRepopulate) {
+  queue_.Emplace(1001, "one");
+  queue_.Emplace(2001, "two");
+
+  ASSERT_TRUE(queue_.Remove(1001));
+  ASSERT_TRUE(queue_.Remove(2001));
+  EXPECT_TRUE(queue_.IsEmpty());
+  EXPECT_EQ(0u, queue_.first_packet());
+  EXPECT_EQ(0u, queue_.last_packet());
+
+  EXPECT_TRUE(queue_.Emplace(101, "one"));
+  EXPECT_TRUE(queue_.Emplace(201, "two"));
+  EXPECT_EQ(101u, queue_.first_packet());
+  EXPECT_EQ(201u, queue_.last_packet());
+}
+
+TEST_F(PacketNumberIndexedQueueTest, FailToRemoveElementsThatNeverExisted) {
+  ASSERT_FALSE(queue_.Remove(1000));
+  queue_.Emplace(1001, "one");
+  ASSERT_FALSE(queue_.Remove(1000));
+  ASSERT_FALSE(queue_.Remove(1002));
+}
+
+TEST_F(PacketNumberIndexedQueueTest, FailToRemoveElementsTwice) {
+  queue_.Emplace(1001, "one");
+  ASSERT_TRUE(queue_.Remove(1001));
+  ASSERT_FALSE(queue_.Remove(1001));
+  ASSERT_FALSE(queue_.Remove(1001));
+}
+
+}  // namespace
+}  // namespace net
diff --git a/net/quic/platform/api/quic_socket_address.cc b/net/quic/platform/api/quic_socket_address.cc
index 43ffa343..fb08034 100644
--- a/net/quic/platform/api/quic_socket_address.cc
+++ b/net/quic/platform/api/quic_socket_address.cc
@@ -20,11 +20,11 @@
 QuicSocketAddress::QuicSocketAddress(const QuicSocketAddressImpl& impl)
     : impl_(impl) {}
 
-bool operator==(QuicSocketAddress lhs, QuicSocketAddress rhs) {
+bool operator==(const QuicSocketAddress& lhs, const QuicSocketAddress& rhs) {
   return lhs.impl_ == rhs.impl_;
 }
 
-bool operator!=(QuicSocketAddress lhs, QuicSocketAddress rhs) {
+bool operator!=(const QuicSocketAddress& lhs, const QuicSocketAddress& rhs) {
   return lhs.impl_ != rhs.impl_;
 }
 
diff --git a/net/quic/platform/api/quic_socket_address.h b/net/quic/platform/api/quic_socket_address.h
index 7d8bcde..8aac753 100644
--- a/net/quic/platform/api/quic_socket_address.h
+++ b/net/quic/platform/api/quic_socket_address.h
@@ -24,10 +24,10 @@
   QuicSocketAddress(const QuicSocketAddress& other) = default;
   QuicSocketAddress& operator=(const QuicSocketAddress& other) = default;
   QuicSocketAddress& operator=(QuicSocketAddress&& other) = default;
-  QUIC_EXPORT_PRIVATE friend bool operator==(QuicSocketAddress lhs,
-                                             QuicSocketAddress rhs);
-  QUIC_EXPORT_PRIVATE friend bool operator!=(QuicSocketAddress lhs,
-                                             QuicSocketAddress rhs);
+  QUIC_EXPORT_PRIVATE friend bool operator==(const QuicSocketAddress& lhs,
+                                             const QuicSocketAddress& rhs);
+  QUIC_EXPORT_PRIVATE friend bool operator!=(const QuicSocketAddress& lhs,
+                                             const QuicSocketAddress& rhs);
 
   bool IsInitialized() const;
   std::string ToString() const;
diff --git a/net/tools/quic/quic_simple_client.cc b/net/tools/quic/quic_simple_client.cc
index 5c2a528..cd47622 100644
--- a/net/tools/quic/quic_simple_client.cc
+++ b/net/tools/quic/quic_simple_client.cc
@@ -154,11 +154,10 @@
 }
 
 bool QuicSimpleClient::OnPacket(const QuicReceivedPacket& packet,
-                                const IPEndPoint& local_address,
-                                const IPEndPoint& peer_address) {
-  session()->connection()->ProcessUdpPacket(
-      QuicSocketAddress(QuicSocketAddressImpl(local_address)),
-      QuicSocketAddress(QuicSocketAddressImpl(peer_address)), packet);
+                                const QuicSocketAddress& local_address,
+                                const QuicSocketAddress& peer_address) {
+  session()->connection()->ProcessUdpPacket(local_address, peer_address,
+                                            packet);
   if (!session()->connection()->connected()) {
     return false;
   }
diff --git a/net/tools/quic/quic_simple_client.h b/net/tools/quic/quic_simple_client.h
index 0eacdf7..b0c25ca 100644
--- a/net/tools/quic/quic_simple_client.h
+++ b/net/tools/quic/quic_simple_client.h
@@ -50,8 +50,8 @@
   // QuicChromiumPacketReader::Visitor
   void OnReadError(int result, const DatagramClientSocket* socket) override;
   bool OnPacket(const QuicReceivedPacket& packet,
-                const IPEndPoint& local_address,
-                const IPEndPoint& peer_address) override;
+                const QuicSocketAddress& local_address,
+                const QuicSocketAddress& peer_address) override;
 
   // From QuicClientBase
   QuicSocketAddress GetLatestClientAddress() const override;
diff --git a/services/ui/gpu/gpu_service.cc b/services/ui/gpu/gpu_service.cc
index 146e5489..0330a13 100644
--- a/services/ui/gpu/gpu_service.cc
+++ b/services/ui/gpu/gpu_service.cc
@@ -14,6 +14,7 @@
 #include "cc/output/in_process_context_provider.h"
 #include "gpu/command_buffer/client/gpu_memory_buffer_manager.h"
 #include "gpu/command_buffer/service/gpu_switches.h"
+#include "gpu/command_buffer/service/scheduler.h"
 #include "gpu/command_buffer/service/sync_point_manager.h"
 #include "gpu/config/gpu_info_collector.h"
 #include "gpu/config/gpu_switches.h"
@@ -96,7 +97,6 @@
       gpu_workarounds_(base::CommandLine::ForCurrentProcess()),
       gpu_info_(gpu_info),
       gpu_feature_info_(gpu_feature_info),
-      sync_point_manager_(nullptr),
       bindings_(base::MakeUnique<mojo::BindingSet<mojom::GpuService>>()),
       weak_ptr_factory_(this) {
   DCHECK(!io_runner_->BelongsToCurrentThread());
@@ -176,13 +176,18 @@
     shutdown_event_ = owned_shutdown_event_.get();
   }
 
+  if (gpu_preferences_.enable_gpu_scheduler) {
+    scheduler_ = base::MakeUnique<gpu::Scheduler>(
+        base::ThreadTaskRunnerHandle::Get(), sync_point_manager_);
+  }
+
   // Defer creation of the render thread. This is to prevent it from handling
   // IPC messages before the sandbox has been enabled and all other necessary
   // initialization has succeeded.
   gpu_channel_manager_.reset(new gpu::GpuChannelManager(
       gpu_preferences_, gpu_workarounds_, this, watchdog_thread_.get(),
-      base::ThreadTaskRunnerHandle::Get(), io_runner_, sync_point_manager_,
-      gpu_memory_buffer_factory_.get(), gpu_feature_info_,
+      base::ThreadTaskRunnerHandle::Get(), io_runner_, scheduler_.get(),
+      sync_point_manager_, gpu_memory_buffer_factory_.get(), gpu_feature_info_,
       std::move(activity_flags)));
 
   media_gpu_channel_manager_.reset(
diff --git a/services/ui/gpu/gpu_service.h b/services/ui/gpu/gpu_service.h
index d6e2d3f..bb42a84 100644
--- a/services/ui/gpu/gpu_service.h
+++ b/services/ui/gpu/gpu_service.h
@@ -29,6 +29,7 @@
 namespace gpu {
 class GpuMemoryBufferFactory;
 class GpuWatchdogThread;
+class Scheduler;
 class SyncPointManager;
 }
 
@@ -183,6 +184,8 @@
   std::unique_ptr<gpu::SyncPointManager> owned_sync_point_manager_;
   gpu::SyncPointManager* sync_point_manager_ = nullptr;
 
+  std::unique_ptr<gpu::Scheduler> scheduler_;
+
   // An event that will be signalled when we shutdown. On some platforms it
   // comes from external sources.
   std::unique_ptr<base::WaitableEvent> owned_shutdown_event_;
diff --git a/services/ui/public/cpp/gpu/context_provider_command_buffer.cc b/services/ui/public/cpp/gpu/context_provider_command_buffer.cc
index 13238158..da0f48d2 100644
--- a/services/ui/public/cpp/gpu/context_provider_command_buffer.cc
+++ b/services/ui/public/cpp/gpu/context_provider_command_buffer.cc
@@ -152,7 +152,7 @@
 ContextProviderCommandBuffer::ContextProviderCommandBuffer(
     scoped_refptr<gpu::GpuChannelHost> channel,
     int32_t stream_id,
-    gpu::GpuStreamPriority stream_priority,
+    gpu::SchedulingPriority stream_priority,
     gpu::SurfaceHandle surface_handle,
     const GURL& active_url,
     bool automatic_flushes,
diff --git a/services/ui/public/cpp/gpu/context_provider_command_buffer.h b/services/ui/public/cpp/gpu/context_provider_command_buffer.h
index 0a5a7c9..a5afb59 100644
--- a/services/ui/public/cpp/gpu/context_provider_command_buffer.h
+++ b/services/ui/public/cpp/gpu/context_provider_command_buffer.h
@@ -18,7 +18,7 @@
 #include "cc/output/context_provider.h"
 #include "gpu/command_buffer/client/shared_memory_limits.h"
 #include "gpu/command_buffer/common/gles2_cmd_utils.h"
-#include "gpu/ipc/common/gpu_stream_constants.h"
+#include "gpu/command_buffer/common/scheduling_priority.h"
 #include "gpu/ipc/common/surface_handle.h"
 #include "services/ui/public/cpp/gpu/command_buffer_metrics.h"
 #include "ui/gl/gpu_preference.h"
@@ -50,7 +50,7 @@
   ContextProviderCommandBuffer(
       scoped_refptr<gpu::GpuChannelHost> channel,
       int32_t stream_id,
-      gpu::GpuStreamPriority stream_priority,
+      gpu::SchedulingPriority stream_priority,
       gpu::SurfaceHandle surface_handle,
       const GURL& active_url,
       bool automatic_flushes,
@@ -112,7 +112,7 @@
   bool bind_failed_ = false;
 
   const int32_t stream_id_;
-  const gpu::GpuStreamPriority stream_priority_;
+  const gpu::SchedulingPriority stream_priority_;
   const gpu::SurfaceHandle surface_handle_;
   const GURL active_url_;
   const bool automatic_flushes_;
diff --git a/services/ui/public/cpp/gpu/gpu.cc b/services/ui/public/cpp/gpu/gpu.cc
index e0073d5..e70ca6f 100644
--- a/services/ui/public/cpp/gpu/gpu.cc
+++ b/services/ui/public/cpp/gpu/gpu.cc
@@ -7,6 +7,7 @@
 #include "base/memory/ptr_util.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "build/build_config.h"
+#include "gpu/command_buffer/common/scheduling_priority.h"
 #include "mojo/public/cpp/bindings/sync_call_restrictions.h"
 #include "mojo/public/cpp/system/platform_handle.h"
 #include "services/service_manager/public/cpp/connector.h"
@@ -59,8 +60,12 @@
 
 scoped_refptr<cc::ContextProvider> Gpu::CreateContextProvider(
     scoped_refptr<gpu::GpuChannelHost> gpu_channel) {
+  int32_t stream_id = 0;
+  gpu::SchedulingPriority stream_priority = gpu::SchedulingPriority::kNormal;
+
   constexpr bool automatic_flushes = false;
   constexpr bool support_locking = false;
+
   gpu::gles2::ContextCreationAttribHelper attributes;
   attributes.alpha_size = -1;
   attributes.depth_size = 0;
@@ -69,12 +74,11 @@
   attributes.sample_buffers = 0;
   attributes.bind_generates_resource = false;
   attributes.lose_context_when_out_of_memory = true;
-  constexpr ui::ContextProviderCommandBuffer* shared_context_provider = nullptr;
+  ui::ContextProviderCommandBuffer* shared_context_provider = nullptr;
   return make_scoped_refptr(new ui::ContextProviderCommandBuffer(
-      std::move(gpu_channel), gpu::GPU_STREAM_DEFAULT,
-      gpu::GpuStreamPriority::NORMAL, gpu::kNullSurfaceHandle,
-      GURL("chrome://gpu/MusContextFactory"), automatic_flushes,
-      support_locking, gpu::SharedMemoryLimits(), attributes,
+      std::move(gpu_channel), stream_id, stream_priority,
+      gpu::kNullSurfaceHandle, GURL("chrome://gpu/MusContextFactory"),
+      automatic_flushes, support_locking, gpu::SharedMemoryLimits(), attributes,
       shared_context_provider, ui::command_buffer_metrics::MUS_CLIENT_CONTEXT));
 }
 
diff --git a/storage/browser/blob/blob_memory_controller.cc b/storage/browser/blob/blob_memory_controller.cc
index 0153f3bc..27370be 100644
--- a/storage/browser/blob/blob_memory_controller.cc
+++ b/storage/browser/blob/blob_memory_controller.cc
@@ -16,6 +16,7 @@
 #include "base/guid.h"
 #include "base/location.h"
 #include "base/memory/ptr_util.h"
+#include "base/metrics/histogram_functions.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/numerics/safe_conversions.h"
 #include "base/numerics/safe_math.h"
@@ -41,6 +42,7 @@
 namespace {
 constexpr int64_t kUnknownDiskAvailability = -1ll;
 constexpr uint64_t kMegabyte = 1024ull * 1024;
+const int64_t kMinSecondsForPressureEvictions = 30;
 
 using FileCreationInfo = BlobMemoryController::FileCreationInfo;
 using MemoryAllocation = BlobMemoryController::MemoryAllocation;
@@ -505,6 +507,9 @@
       disk_space_function_(&base::SysInfo::AmountOfFreeDiskSpace),
       populated_memory_items_(
           base::MRUCache<uint64_t, ShareableBlobDataItem*>::NO_AUTO_EVICT),
+      memory_pressure_listener_(
+          base::Bind(&BlobMemoryController::OnMemoryPressure,
+                     base::Unretained(this))),
       weak_factory_(this) {}
 
 BlobMemoryController::~BlobMemoryController() {}
@@ -604,7 +609,8 @@
   if (total_bytes_needed <= GetAvailableMemoryForBlobs()) {
     GrantMemoryAllocations(&unreserved_memory_items,
                            static_cast<size_t>(total_bytes_needed));
-    MaybeScheduleEvictionUntilSystemHealthy();
+    MaybeScheduleEvictionUntilSystemHealthy(
+        base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE);
     done_callback.Run(true);
     return base::WeakPtr<QuotaAllocationTask>();
   }
@@ -615,7 +621,8 @@
 
   auto weak_ptr = AppendMemoryTask(
       total_bytes_needed, std::move(unreserved_memory_items), done_callback);
-  MaybeScheduleEvictionUntilSystemHealthy();
+  MaybeScheduleEvictionUntilSystemHealthy(
+      base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE);
   return weak_ptr;
 }
 
@@ -649,7 +656,8 @@
       populated_memory_items_.Put(item->item_id(), item.get());
     }
   }
-  MaybeScheduleEvictionUntilSystemHealthy();
+  MaybeScheduleEvictionUntilSystemHealthy(
+      base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE);
 }
 
 void BlobMemoryController::CalculateBlobStorageLimits() {
@@ -771,11 +779,12 @@
 }
 
 size_t BlobMemoryController::CollectItemsForEviction(
-    std::vector<scoped_refptr<ShareableBlobDataItem>>* output) {
+    std::vector<scoped_refptr<ShareableBlobDataItem>>* output,
+    uint64_t min_page_file_size) {
   base::CheckedNumeric<size_t> total_items_size = 0;
   // Process the recent item list and remove items until we have at least a
   // minimum file size or we're at the end of our items to page to disk.
-  while (total_items_size.ValueOrDie() < limits_.min_page_file_size &&
+  while (total_items_size.ValueOrDie() < min_page_file_size &&
          !populated_memory_items_.empty()) {
     auto iterator = --populated_memory_items_.end();
     ShareableBlobDataItem* item = iterator->second;
@@ -789,7 +798,8 @@
   return total_items_size.ValueOrDie();
 }
 
-void BlobMemoryController::MaybeScheduleEvictionUntilSystemHealthy() {
+void BlobMemoryController::MaybeScheduleEvictionUntilSystemHealthy(
+    base::MemoryPressureListener::MemoryPressureLevel memory_pressure_level) {
   // Don't do eviction when others are happening, as we don't change our
   // pending_memory_quota_total_size_ value until after the paging files have
   // been written.
@@ -800,20 +810,42 @@
       static_cast<uint64_t>(pending_memory_quota_total_size_) +
       blob_memory_used_;
 
+  size_t in_memory_limit = limits_.memory_limit_before_paging();
+  uint64_t min_page_file_size = limits_.min_page_file_size;
+  if (memory_pressure_level !=
+      base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE) {
+    in_memory_limit = 0;
+    // Use lower page file size to reduce using more memory for writing under
+    // pressure.
+    min_page_file_size = limits_.max_blob_in_memory_space *
+                         limits_.max_blob_in_memory_space_under_pressure_ratio;
+  }
+
   // We try to page items to disk until our current system size + requested
   // memory is below our size limit.
   // Size limit is a lower |memory_limit_before_paging()| if we have disk space.
   while (total_memory_usage > limits_.effective_max_disk_space ||
          (disk_used_ < limits_.effective_max_disk_space &&
-          total_memory_usage > limits_.memory_limit_before_paging())) {
+          total_memory_usage > in_memory_limit)) {
+    const char* reason = nullptr;
+    if (memory_pressure_level !=
+        base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE) {
+      reason = "OnMemoryPressure";
+    } else if (total_memory_usage > limits_.effective_max_disk_space) {
+      reason = "SizeExceededMaxDiskSpace";
+    } else {
+      reason = "SizeExceededInMemoryLimit";
+    }
+
     // We only page when we have enough items to fill a whole page file.
-    if (populated_memory_items_bytes_ < limits_.min_page_file_size)
+    if (populated_memory_items_bytes_ < min_page_file_size)
       break;
-    DCHECK_LE(limits_.min_page_file_size,
-              static_cast<uint64_t>(blob_memory_used_));
+    DCHECK_LE(min_page_file_size, static_cast<uint64_t>(blob_memory_used_));
 
     std::vector<scoped_refptr<ShareableBlobDataItem>> items_to_swap;
-    size_t total_items_size = CollectItemsForEviction(&items_to_swap);
+
+    size_t total_items_size =
+        CollectItemsForEviction(&items_to_swap, min_page_file_size);
     if (total_items_size == 0)
       break;
 
@@ -849,7 +881,10 @@
                    total_items_size),
         base::Bind(&BlobMemoryController::OnEvictionComplete,
                    weak_factory_.GetWeakPtr(), base::Passed(&file_reference),
-                   base::Passed(&items_to_swap), total_items_size));
+                   base::Passed(&items_to_swap), total_items_size, reason,
+                   total_memory_usage));
+
+    last_eviction_time_ = base::TimeTicks::Now();
   }
   RecordTracingCounters();
 }
@@ -858,6 +893,8 @@
     scoped_refptr<ShareableFileReference> file_reference,
     std::vector<scoped_refptr<ShareableBlobDataItem>> items,
     size_t total_items_size,
+    const char* evict_reason,
+    size_t memory_usage_before_eviction,
     std::pair<FileCreationInfo, int64_t /* avail_disk */> result) {
   if (!file_paging_enabled_)
     return;
@@ -893,12 +930,32 @@
   }
   in_flight_memory_used_ -= total_items_size;
 
+  // Record change in memory usage at the last eviction reply.
+  size_t total_usage = blob_memory_used_ + pending_memory_quota_total_size_;
+  if (!pending_evictions_ && memory_usage_before_eviction >= total_usage) {
+    std::string full_histogram_name =
+        std::string("Storage.Blob.SizeEvictedToDiskInKB.") + evict_reason;
+    base::UmaHistogramCounts100000(
+        full_histogram_name,
+        (memory_usage_before_eviction - total_usage) / 1024);
+  }
+
   // We want callback on blobs up to the amount we've freed.
   MaybeGrantPendingMemoryRequests();
 
   // If we still have more blobs waiting and we're not waiting on more paging
   // operations, schedule more.
-  MaybeScheduleEvictionUntilSystemHealthy();
+  MaybeScheduleEvictionUntilSystemHealthy(
+      base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE);
+}
+
+void BlobMemoryController::OnMemoryPressure(
+    base::MemoryPressureListener::MemoryPressureLevel memory_pressure_level) {
+  auto time_from_last_evicion = base::TimeTicks::Now() - last_eviction_time_;
+  if (time_from_last_evicion.InSeconds() < kMinSecondsForPressureEvictions)
+    return;
+
+  MaybeScheduleEvictionUntilSystemHealthy(memory_pressure_level);
 }
 
 FilePath BlobMemoryController::GenerateNextPageFileName() {
diff --git a/storage/browser/blob/blob_memory_controller.h b/storage/browser/blob/blob_memory_controller.h
index eb29518..7c72d0f 100644
--- a/storage/browser/blob/blob_memory_controller.h
+++ b/storage/browser/blob/blob_memory_controller.h
@@ -21,7 +21,9 @@
 #include "base/containers/mru_cache.h"
 #include "base/files/file.h"
 #include "base/files/file_path.h"
+#include "base/gtest_prod_util.h"
 #include "base/macros.h"
+#include "base/memory/memory_pressure_listener.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
 #include "base/optional.h"
@@ -178,6 +180,7 @@
   class FileQuotaAllocationTask;
   class MemoryQuotaAllocationTask;
 
+  FRIEND_TEST_ALL_PREFIXES(BlobMemoryControllerTest, OnMemoryPressure);
   // So this (and only this) class can call CalculateBlobStorageLimits().
   friend class content::ChromeBlobStorageContext;
 
@@ -205,10 +208,12 @@
   void MaybeGrantPendingMemoryRequests();
 
   size_t CollectItemsForEviction(
-      std::vector<scoped_refptr<ShareableBlobDataItem>>* output);
+      std::vector<scoped_refptr<ShareableBlobDataItem>>* output,
+      uint64_t min_page_file_size);
 
   // Schedule paging until our memory usage is below our memory limit.
-  void MaybeScheduleEvictionUntilSystemHealthy();
+  void MaybeScheduleEvictionUntilSystemHealthy(
+      base::MemoryPressureListener::MemoryPressureLevel level);
 
   // Called when we've completed evicting a list of items to disk. This is where
   // we swap the bytes items for file items, and update our bookkeeping.
@@ -216,7 +221,12 @@
       scoped_refptr<ShareableFileReference> file_reference,
       std::vector<scoped_refptr<ShareableBlobDataItem>> items,
       size_t total_items_size,
-      std::pair<FileCreationInfo, int64_t /* disk_avail */> result);
+      const char* evict_reason,
+      size_t memory_usage_before_eviction,
+      std::pair<FileCreationInfo, int64_t /* avail_disk */> result);
+
+  void OnMemoryPressure(
+      base::MemoryPressureListener::MemoryPressureLevel memory_pressure_level);
 
   size_t GetAvailableMemoryForBlobs() const;
   uint64_t GetAvailableFileSpaceForBlobs() const;
@@ -265,6 +275,7 @@
   scoped_refptr<base::TaskRunner> file_runner_;
   // This defaults to calling base::SysInfo::AmountOfFreeDiskSpace.
   DiskSpaceFuncPtr disk_space_function_;
+  base::TimeTicks last_eviction_time_;
 
   // Lifetime of the ShareableBlobDataItem objects is handled externally in the
   // BlobStorageContext class.
@@ -275,6 +286,8 @@
   // item to the recent_item_cache_ above.
   std::unordered_set<uint64_t> items_paging_to_file_;
 
+  base::MemoryPressureListener memory_pressure_listener_;
+
   base::WeakPtrFactory<BlobMemoryController> weak_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(BlobMemoryController);
diff --git a/storage/browser/blob/blob_memory_controller_unittest.cc b/storage/browser/blob/blob_memory_controller_unittest.cc
index 918315b3..2ab02f0e 100644
--- a/storage/browser/blob/blob_memory_controller_unittest.cc
+++ b/storage/browser/blob/blob_memory_controller_unittest.cc
@@ -31,6 +31,7 @@
 const size_t kTestBlobStorageIPCThresholdBytes = 20;
 const size_t kTestBlobStorageMaxSharedMemoryBytes = 50;
 const size_t kTestBlobStorageMaxBlobMemorySize = 500;
+const float kTestMaxBlobInMemorySpaceUnderPressureRatio = 0.004f;
 const uint64_t kTestBlobStorageMaxDiskSpace = 1000;
 const uint64_t kTestBlobStorageMinFileSizeBytes = 10;
 const uint64_t kTestBlobStorageMaxFileSizeBytes = 100;
@@ -88,6 +89,8 @@
     limits.max_ipc_memory_size = kTestBlobStorageIPCThresholdBytes;
     limits.max_shared_memory_size = kTestBlobStorageMaxSharedMemoryBytes;
     limits.max_blob_in_memory_space = kTestBlobStorageMaxBlobMemorySize;
+    limits.max_blob_in_memory_space_under_pressure_ratio =
+        kTestMaxBlobInMemorySpaceUnderPressureRatio;
     limits.desired_max_disk_space = kTestBlobStorageMaxDiskSpace;
     limits.effective_max_disk_space = kTestBlobStorageMaxDiskSpace;
     limits.min_page_file_size = kTestBlobStorageMinFileSizeBytes;
@@ -100,6 +103,8 @@
     limits.max_ipc_memory_size = kTestBlobStorageIPCThresholdBytes;
     limits.max_shared_memory_size = kTestBlobStorageMaxSharedMemoryBytes;
     limits.max_blob_in_memory_space = kTestBlobStorageMaxBlobMemorySize;
+    limits.max_blob_in_memory_space_under_pressure_ratio =
+        kTestMaxBlobInMemorySpaceUnderPressureRatio;
     limits.desired_max_disk_space = kTestSmallBlobStorageMaxDiskSpace;
     limits.effective_max_disk_space = kTestSmallBlobStorageMaxDiskSpace;
     limits.min_page_file_size = kTestBlobStorageMinFileSizeBytes;
@@ -1120,4 +1125,48 @@
   EXPECT_FALSE(controller.limits().IsDiskSpaceConstrained());
 }
 
+TEST_F(BlobMemoryControllerTest, OnMemoryPressure) {
+  BlobMemoryController controller(temp_dir_.GetPath(), file_runner_);
+  SetTestMemoryLimits(&controller);
+  AssertEnoughDiskSpace();
+
+  char kData[1];
+  kData[0] = 'e';
+
+  std::vector<scoped_refptr<ShareableBlobDataItem>> small_items;
+  size_t size_to_load = 2 * kTestBlobStorageMaxBlobMemorySize *
+                            kTestMaxBlobInMemorySpaceUnderPressureRatio +
+                        1;
+  for (size_t i = 0; i < size_to_load; i++) {
+    BlobDataBuilder builder("fake");
+    builder.AppendData(kData, 1);
+    std::vector<scoped_refptr<ShareableBlobDataItem>> items =
+        CreateSharedDataItems(builder);
+    base::WeakPtr<QuotaAllocationTask> memory_task =
+        controller.ReserveMemoryQuota(items, GetMemoryRequestCallback());
+    EXPECT_FALSE(memory_task);
+    items[0]->set_state(ItemState::POPULATED_WITH_QUOTA);
+    small_items.insert(small_items.end(), items.begin(), items.end());
+  }
+  controller.NotifyMemoryItemsUsed(small_items);
+  EXPECT_FALSE(file_runner_->HasPendingTask());
+  EXPECT_EQ(size_to_load, controller.memory_usage());
+
+  controller.OnMemoryPressure(
+      base::MemoryPressureListener::MemoryPressureLevel::
+          MEMORY_PRESSURE_LEVEL_CRITICAL);
+
+  EXPECT_TRUE(file_runner_->HasPendingTask());
+  RunFileThreadTasks();
+
+  base::RunLoop().RunUntilIdle();
+
+  // 2 page files of size |kTestBlobStorageMaxBlobMemorySize *
+  // kTestMaxBlobInMemorySpaceUnderPressureRatio| should be evicted with 1 byte
+  // left in-memory.
+  EXPECT_EQ(1u, controller.memory_usage());
+  EXPECT_EQ(size_to_load - 1, controller.disk_usage());
+  return;
+}
+
 }  // namespace storage
diff --git a/storage/common/blob_storage/blob_storage_constants.h b/storage/common/blob_storage/blob_storage_constants.h
index f51b012..4a4e207a 100644
--- a/storage/common/blob_storage/blob_storage_constants.h
+++ b/storage/common/blob_storage/blob_storage_constants.h
@@ -23,8 +23,10 @@
 #if defined(OS_ANDROID)
 // On minimal Android maximum in-memory space can be as low as 5MB.
 constexpr uint64_t kDefaultMinPageFileSize = 5ull * 1024 * 1024 / 2;
+const float kDefaultMaxBlobInMemorySpaceUnderPressureRatio = 0.02f;
 #else
 constexpr uint64_t kDefaultMinPageFileSize = 5ull * 1024 * 1024;
+const float kDefaultMaxBlobInMemorySpaceUnderPressureRatio = 0.002f;
 #endif
 
 // All sizes are in bytes.
@@ -52,6 +54,12 @@
 
   // This is the maximum amount of memory we can use to store blobs.
   size_t max_blob_in_memory_space = kDefaultMaxBlobInMemorySpace;
+  // The ratio applied to |max_blob_in_memory_space| to reduce memory usage
+  // under memory pressure. Note: Under pressure we modify the
+  // |min_page_file_size| to ensure we can evict items until we get below the
+  // reduced memory limit.
+  float max_blob_in_memory_space_under_pressure_ratio =
+      kDefaultMaxBlobInMemorySpaceUnderPressureRatio;
 
   // This is the maximum amount of disk space we can use.
   uint64_t desired_max_disk_space = kDefaultMaxBlobDiskSpace;
diff --git a/testing/buildbot/chromium.android.fyi.json b/testing/buildbot/chromium.android.fyi.json
index 41f9d0e..bd907a3 100644
--- a/testing/buildbot/chromium.android.fyi.json
+++ b/testing/buildbot/chromium.android.fyi.json
@@ -30,9 +30,6 @@
         "test": "base_unittests"
       },
       {
-        "override_compile_targets": [
-          "breakpad_unittests"
-        ],
         "test": "breakpad_unittests"
       },
       {
@@ -87,9 +84,6 @@
         "test": "net_unittests"
       },
       {
-        "override_compile_targets": [
-          "sandbox_linux_unittests"
-        ],
         "test": "sandbox_linux_unittests"
       },
       {
@@ -132,9 +126,6 @@
         "test": "base_unittests"
       },
       {
-        "override_compile_targets": [
-          "breakpad_unittests"
-        ],
         "test": "breakpad_unittests"
       },
       {
@@ -189,9 +180,6 @@
         "test": "net_unittests"
       },
       {
-        "override_compile_targets": [
-          "sandbox_linux_unittests"
-        ],
         "test": "sandbox_linux_unittests"
       },
       {
@@ -231,7 +219,6 @@
   "Lollipop Low-end Tester": {
     "gtest_tests": [
       {
-        "override_isolate_target": "android_webview_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -246,7 +233,6 @@
         "test": "android_webview_unittests"
       },
       {
-        "override_isolate_target": "base_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -261,7 +247,6 @@
         "test": "base_unittests"
       },
       {
-        "override_isolate_target": "blink_heap_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -276,7 +261,6 @@
         "test": "blink_heap_unittests"
       },
       {
-        "override_isolate_target": "breakpad_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -291,7 +275,6 @@
         "test": "breakpad_unittests"
       },
       {
-        "override_isolate_target": "capture_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -306,7 +289,6 @@
         "test": "capture_unittests"
       },
       {
-        "override_isolate_target": "cc_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -321,10 +303,6 @@
         "test": "cc_unittests"
       },
       {
-        "override_compile_targets": [
-          "chrome_public_test_apk"
-        ],
-        "override_isolate_target": "chrome_public_test_apk",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -340,10 +318,6 @@
         "test": "chrome_public_test_apk"
       },
       {
-        "override_compile_targets": [
-          "chrome_sync_shell_test_apk"
-        ],
-        "override_isolate_target": "chrome_sync_shell_test_apk",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -358,7 +332,6 @@
         "test": "chrome_sync_shell_test_apk"
       },
       {
-        "override_isolate_target": "components_browsertests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -373,7 +346,6 @@
         "test": "components_browsertests"
       },
       {
-        "override_isolate_target": "components_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -388,7 +360,6 @@
         "test": "components_unittests"
       },
       {
-        "override_isolate_target": "content_browsertests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -404,10 +375,6 @@
         "test": "content_browsertests"
       },
       {
-        "override_compile_targets": [
-          "content_shell_test_apk"
-        ],
-        "override_isolate_target": "content_shell_test_apk",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -422,7 +389,6 @@
         "test": "content_shell_test_apk"
       },
       {
-        "override_isolate_target": "content_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -437,7 +403,6 @@
         "test": "content_unittests"
       },
       {
-        "override_isolate_target": "device_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -452,7 +417,6 @@
         "test": "device_unittests"
       },
       {
-        "override_isolate_target": "events_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -467,7 +431,6 @@
         "test": "events_unittests"
       },
       {
-        "override_isolate_target": "gl_tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -482,7 +445,6 @@
         "test": "gl_tests"
       },
       {
-        "override_isolate_target": "gl_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -497,7 +459,6 @@
         "test": "gl_unittests"
       },
       {
-        "override_isolate_target": "gpu_ipc_service_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -512,7 +473,6 @@
         "test": "gpu_ipc_service_unittests"
       },
       {
-        "override_isolate_target": "gpu_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -527,7 +487,6 @@
         "test": "gpu_unittests"
       },
       {
-        "override_isolate_target": "ipc_tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -542,7 +501,6 @@
         "test": "ipc_tests"
       },
       {
-        "override_isolate_target": "latency_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -557,7 +515,6 @@
         "test": "latency_unittests"
       },
       {
-        "override_isolate_target": "media_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -572,7 +529,6 @@
         "test": "media_unittests"
       },
       {
-        "override_isolate_target": "net_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -587,7 +543,6 @@
         "test": "net_unittests"
       },
       {
-        "override_isolate_target": "sandbox_linux_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -602,7 +557,6 @@
         "test": "sandbox_linux_unittests"
       },
       {
-        "override_isolate_target": "sql_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -617,7 +571,6 @@
         "test": "sql_unittests"
       },
       {
-        "override_isolate_target": "storage_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -632,7 +585,6 @@
         "test": "storage_unittests"
       },
       {
-        "override_isolate_target": "ui_android_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -647,7 +599,6 @@
         "test": "ui_android_unittests"
       },
       {
-        "override_isolate_target": "ui_base_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -662,7 +613,6 @@
         "test": "ui_base_unittests"
       },
       {
-        "override_isolate_target": "ui_touch_selection_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -677,7 +627,6 @@
         "test": "ui_touch_selection_unittests"
       },
       {
-        "override_isolate_target": "unit_tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -692,10 +641,6 @@
         "test": "unit_tests"
       },
       {
-        "override_compile_targets": [
-          "webview_instrumentation_test_apk"
-        ],
-        "override_isolate_target": "webview_instrumentation_test_apk",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -726,9 +671,6 @@
         ],
         "isolate_name": "telemetry_perf_tests",
         "name": "system_health.memory_mobile",
-        "override_compile_targets": [
-          "telemetry_perf_tests"
-        ],
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -746,7 +688,6 @@
   "Nougat Phone Tester": {
     "gtest_tests": [
       {
-        "override_isolate_target": "android_webview_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -779,7 +720,6 @@
         "test": "android_webview_unittests"
       },
       {
-        "override_isolate_target": "base_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -812,10 +752,6 @@
         "test": "base_unittests"
       },
       {
-        "override_compile_targets": [
-          "breakpad_unittests"
-        ],
-        "override_isolate_target": "breakpad_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -848,7 +784,6 @@
         "test": "breakpad_unittests"
       },
       {
-        "override_isolate_target": "capture_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -881,7 +816,6 @@
         "test": "capture_unittests"
       },
       {
-        "override_isolate_target": "cc_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -914,10 +848,6 @@
         "test": "cc_unittests"
       },
       {
-        "override_compile_targets": [
-          "chrome_public_test_apk"
-        ],
-        "override_isolate_target": "chrome_public_test_apk",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -951,10 +881,6 @@
         "test": "chrome_public_test_apk"
       },
       {
-        "override_compile_targets": [
-          "chrome_sync_shell_test_apk"
-        ],
-        "override_isolate_target": "chrome_sync_shell_test_apk",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -987,7 +913,6 @@
         "test": "chrome_sync_shell_test_apk"
       },
       {
-        "override_isolate_target": "components_browsertests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -1020,7 +945,6 @@
         "test": "components_browsertests"
       },
       {
-        "override_isolate_target": "components_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -1053,7 +977,6 @@
         "test": "components_unittests"
       },
       {
-        "override_isolate_target": "content_browsertests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -1087,10 +1010,6 @@
         "test": "content_browsertests"
       },
       {
-        "override_compile_targets": [
-          "content_shell_test_apk"
-        ],
-        "override_isolate_target": "content_shell_test_apk",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -1124,7 +1043,6 @@
         "test": "content_shell_test_apk"
       },
       {
-        "override_isolate_target": "content_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -1158,7 +1076,6 @@
         "test": "content_unittests"
       },
       {
-        "override_isolate_target": "device_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -1191,7 +1108,6 @@
         "test": "device_unittests"
       },
       {
-        "override_isolate_target": "events_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -1224,7 +1140,6 @@
         "test": "events_unittests"
       },
       {
-        "override_isolate_target": "gfx_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -1257,7 +1172,6 @@
         "test": "gfx_unittests"
       },
       {
-        "override_isolate_target": "gl_tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -1290,7 +1204,6 @@
         "test": "gl_tests"
       },
       {
-        "override_isolate_target": "gl_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -1323,7 +1236,6 @@
         "test": "gl_unittests"
       },
       {
-        "override_isolate_target": "gpu_ipc_service_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -1356,7 +1268,6 @@
         "test": "gpu_ipc_service_unittests"
       },
       {
-        "override_isolate_target": "gpu_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -1389,7 +1300,6 @@
         "test": "gpu_unittests"
       },
       {
-        "override_isolate_target": "ipc_tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -1422,7 +1332,6 @@
         "test": "ipc_tests"
       },
       {
-        "override_isolate_target": "media_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -1455,7 +1364,6 @@
         "test": "media_unittests"
       },
       {
-        "override_isolate_target": "net_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -1489,10 +1397,6 @@
         "test": "net_unittests"
       },
       {
-        "override_compile_targets": [
-          "sandbox_linux_unittests"
-        ],
-        "override_isolate_target": "sandbox_linux_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -1525,7 +1429,6 @@
         "test": "sandbox_linux_unittests"
       },
       {
-        "override_isolate_target": "sql_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -1558,7 +1461,6 @@
         "test": "sql_unittests"
       },
       {
-        "override_isolate_target": "storage_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -1591,7 +1493,6 @@
         "test": "storage_unittests"
       },
       {
-        "override_isolate_target": "ui_android_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -1624,7 +1525,6 @@
         "test": "ui_android_unittests"
       },
       {
-        "override_isolate_target": "ui_base_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -1657,7 +1557,6 @@
         "test": "ui_base_unittests"
       },
       {
-        "override_isolate_target": "ui_touch_selection_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -1690,7 +1589,6 @@
         "test": "ui_touch_selection_unittests"
       },
       {
-        "override_isolate_target": "unit_tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -1723,7 +1621,6 @@
         "test": "unit_tests"
       },
       {
-        "override_isolate_target": "vr_shell_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -1756,10 +1653,6 @@
         "test": "vr_shell_unittests"
       },
       {
-        "override_compile_targets": [
-          "webview_instrumentation_test_apk"
-        ],
-        "override_isolate_target": "webview_instrumentation_test_apk",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -1809,9 +1702,6 @@
         "test": "base_unittests"
       },
       {
-        "override_compile_targets": [
-          "breakpad_unittests"
-        ],
         "swarming": {
           "can_use_on_swarming_builders": false
         },
@@ -1922,9 +1812,6 @@
         "test": "net_unittests"
       },
       {
-        "override_compile_targets": [
-          "sandbox_linux_unittests"
-        ],
         "swarming": {
           "can_use_on_swarming_builders": false
         },
@@ -2003,9 +1890,6 @@
         "test": "base_unittests"
       },
       {
-        "override_compile_targets": [
-          "breakpad_unittests"
-        ],
         "swarming": {
           "can_use_on_swarming_builders": false
         },
@@ -2116,9 +2000,6 @@
         "test": "net_unittests"
       },
       {
-        "override_compile_targets": [
-          "sandbox_linux_unittests"
-        ],
         "swarming": {
           "can_use_on_swarming_builders": false
         },
@@ -2185,7 +2066,6 @@
   "x64 Device Tester": {
     "gtest_tests": [
       {
-        "override_isolate_target": "angle_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -2198,7 +2078,6 @@
         "test": "angle_unittests"
       },
       {
-        "override_isolate_target": "base_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -2211,7 +2090,6 @@
         "test": "base_unittests"
       },
       {
-        "override_isolate_target": "blink_heap_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -2224,7 +2102,6 @@
         "test": "blink_heap_unittests"
       },
       {
-        "override_isolate_target": "breakpad_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -2237,7 +2114,6 @@
         "test": "breakpad_unittests"
       },
       {
-        "override_isolate_target": "cacheinvalidation_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -2250,7 +2126,6 @@
         "test": "cacheinvalidation_unittests"
       },
       {
-        "override_isolate_target": "capture_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -2263,7 +2138,6 @@
         "test": "capture_unittests"
       },
       {
-        "override_isolate_target": "cast_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -2276,7 +2150,6 @@
         "test": "cast_unittests"
       },
       {
-        "override_isolate_target": "cc_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -2289,10 +2162,6 @@
         "test": "cc_unittests"
       },
       {
-        "override_compile_targets": [
-          "chrome_public_test_apk"
-        ],
-        "override_isolate_target": "chrome_public_test_apk",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -2305,10 +2174,6 @@
         "test": "chrome_public_test_apk"
       },
       {
-        "override_compile_targets": [
-          "chrome_sync_shell_test_apk"
-        ],
-        "override_isolate_target": "chrome_sync_shell_test_apk",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -2321,7 +2186,6 @@
         "test": "chrome_sync_shell_test_apk"
       },
       {
-        "override_isolate_target": "components_browsertests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -2334,7 +2198,6 @@
         "test": "components_browsertests"
       },
       {
-        "override_isolate_target": "components_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -2347,7 +2210,6 @@
         "test": "components_unittests"
       },
       {
-        "override_isolate_target": "content_browsertests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -2360,10 +2222,6 @@
         "test": "content_browsertests"
       },
       {
-        "override_compile_targets": [
-          "content_shell_test_apk"
-        ],
-        "override_isolate_target": "content_shell_test_apk",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -2376,7 +2234,6 @@
         "test": "content_shell_test_apk"
       },
       {
-        "override_isolate_target": "content_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -2389,7 +2246,6 @@
         "test": "content_unittests"
       },
       {
-        "override_isolate_target": "crypto_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -2402,7 +2258,6 @@
         "test": "crypto_unittests"
       },
       {
-        "override_isolate_target": "device_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -2415,7 +2270,6 @@
         "test": "device_unittests"
       },
       {
-        "override_isolate_target": "display_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -2428,7 +2282,6 @@
         "test": "display_unittests"
       },
       {
-        "override_isolate_target": "events_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -2441,7 +2294,6 @@
         "test": "events_unittests"
       },
       {
-        "override_isolate_target": "gcm_unit_tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -2454,7 +2306,6 @@
         "test": "gcm_unit_tests"
       },
       {
-        "override_isolate_target": "gfx_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -2467,7 +2318,6 @@
         "test": "gfx_unittests"
       },
       {
-        "override_isolate_target": "gl_tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -2480,7 +2330,6 @@
         "test": "gl_tests"
       },
       {
-        "override_isolate_target": "gl_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -2493,7 +2342,6 @@
         "test": "gl_unittests"
       },
       {
-        "override_isolate_target": "google_apis_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -2506,7 +2354,6 @@
         "test": "google_apis_unittests"
       },
       {
-        "override_isolate_target": "gpu_ipc_service_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -2519,7 +2366,6 @@
         "test": "gpu_ipc_service_unittests"
       },
       {
-        "override_isolate_target": "gpu_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -2532,7 +2378,6 @@
         "test": "gpu_unittests"
       },
       {
-        "override_isolate_target": "ipc_tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -2545,7 +2390,6 @@
         "test": "ipc_tests"
       },
       {
-        "override_isolate_target": "jingle_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -2558,7 +2402,6 @@
         "test": "jingle_unittests"
       },
       {
-        "override_isolate_target": "media_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -2571,7 +2414,6 @@
         "test": "media_unittests"
       },
       {
-        "override_isolate_target": "midi_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -2584,7 +2426,6 @@
         "test": "midi_unittests"
       },
       {
-        "override_isolate_target": "mojo_common_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -2597,7 +2438,6 @@
         "test": "mojo_common_unittests"
       },
       {
-        "override_isolate_target": "mojo_public_bindings_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -2610,7 +2450,6 @@
         "test": "mojo_public_bindings_unittests"
       },
       {
-        "override_isolate_target": "mojo_public_system_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -2623,7 +2462,6 @@
         "test": "mojo_public_system_unittests"
       },
       {
-        "override_isolate_target": "mojo_system_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -2636,7 +2474,6 @@
         "test": "mojo_system_unittests"
       },
       {
-        "override_isolate_target": "net_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -2649,7 +2486,6 @@
         "test": "net_unittests"
       },
       {
-        "override_isolate_target": "remoting_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -2662,7 +2498,6 @@
         "test": "remoting_unittests"
       },
       {
-        "override_isolate_target": "sandbox_linux_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -2675,7 +2510,6 @@
         "test": "sandbox_linux_unittests"
       },
       {
-        "override_isolate_target": "skia_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -2688,7 +2522,6 @@
         "test": "skia_unittests"
       },
       {
-        "override_isolate_target": "sql_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -2701,7 +2534,6 @@
         "test": "sql_unittests"
       },
       {
-        "override_isolate_target": "storage_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -2714,7 +2546,6 @@
         "test": "storage_unittests"
       },
       {
-        "override_isolate_target": "ui_android_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -2727,7 +2558,6 @@
         "test": "ui_android_unittests"
       },
       {
-        "override_isolate_target": "ui_base_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -2740,7 +2570,6 @@
         "test": "ui_base_unittests"
       },
       {
-        "override_isolate_target": "ui_touch_selection_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -2753,7 +2582,6 @@
         "test": "ui_touch_selection_unittests"
       },
       {
-        "override_isolate_target": "unit_tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -2766,7 +2594,6 @@
         "test": "unit_tests"
       },
       {
-        "override_isolate_target": "url_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -2779,7 +2606,6 @@
         "test": "url_unittests"
       },
       {
-        "override_isolate_target": "webkit_unit_tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -2792,10 +2618,6 @@
         "test": "webkit_unit_tests"
       },
       {
-        "override_compile_targets": [
-          "webview_instrumentation_test_apk"
-        ],
-        "override_isolate_target": "webview_instrumentation_test_apk",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -2808,7 +2630,6 @@
         "test": "webview_instrumentation_test_apk"
       },
       {
-        "override_isolate_target": "wtf_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -2825,7 +2646,6 @@
   "x86 Cloud Tester": {
     "gtest_tests": [
       {
-        "override_isolate_target": "android_webview_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -2838,7 +2658,6 @@
         "test": "android_webview_unittests"
       },
       {
-        "override_isolate_target": "base_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -2851,7 +2670,6 @@
         "test": "base_unittests"
       },
       {
-        "override_isolate_target": "blink_heap_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -2865,7 +2683,6 @@
         "test": "blink_heap_unittests"
       },
       {
-        "override_isolate_target": "breakpad_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -2878,7 +2695,6 @@
         "test": "breakpad_unittests"
       },
       {
-        "override_isolate_target": "capture_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -2891,7 +2707,6 @@
         "test": "capture_unittests"
       },
       {
-        "override_isolate_target": "cc_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -2904,10 +2719,6 @@
         "test": "cc_unittests"
       },
       {
-        "override_compile_targets": [
-          "chrome_public_test_apk"
-        ],
-        "override_isolate_target": "chrome_public_test_apk",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -2921,10 +2732,6 @@
         "test": "chrome_public_test_apk"
       },
       {
-        "override_compile_targets": [
-          "chrome_sync_shell_test_apk"
-        ],
-        "override_isolate_target": "chrome_sync_shell_test_apk",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -2938,7 +2745,6 @@
         "test": "chrome_sync_shell_test_apk"
       },
       {
-        "override_isolate_target": "components_browsertests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -2951,7 +2757,6 @@
         "test": "components_browsertests"
       },
       {
-        "override_isolate_target": "components_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -2964,7 +2769,6 @@
         "test": "components_unittests"
       },
       {
-        "override_isolate_target": "content_browsertests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -2978,10 +2782,6 @@
         "test": "content_browsertests"
       },
       {
-        "override_compile_targets": [
-          "content_shell_test_apk"
-        ],
-        "override_isolate_target": "content_shell_test_apk",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -2995,7 +2795,6 @@
         "test": "content_shell_test_apk"
       },
       {
-        "override_isolate_target": "content_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -3008,7 +2807,6 @@
         "test": "content_unittests"
       },
       {
-        "override_isolate_target": "device_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -3021,7 +2819,6 @@
         "test": "device_unittests"
       },
       {
-        "override_isolate_target": "events_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -3034,7 +2831,6 @@
         "test": "events_unittests"
       },
       {
-        "override_isolate_target": "gl_tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -3047,7 +2843,6 @@
         "test": "gl_tests"
       },
       {
-        "override_isolate_target": "gl_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -3061,7 +2856,6 @@
         "test": "gl_unittests"
       },
       {
-        "override_isolate_target": "gpu_ipc_service_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -3074,7 +2868,6 @@
         "test": "gpu_ipc_service_unittests"
       },
       {
-        "override_isolate_target": "gpu_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -3087,7 +2880,6 @@
         "test": "gpu_unittests"
       },
       {
-        "override_isolate_target": "ipc_tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -3100,7 +2892,6 @@
         "test": "ipc_tests"
       },
       {
-        "override_isolate_target": "media_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -3113,7 +2904,6 @@
         "test": "media_unittests"
       },
       {
-        "override_isolate_target": "mojo_common_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -3127,7 +2917,6 @@
         "test": "mojo_common_unittests"
       },
       {
-        "override_isolate_target": "mojo_public_bindings_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -3141,7 +2930,6 @@
         "test": "mojo_public_bindings_unittests"
       },
       {
-        "override_isolate_target": "mojo_public_system_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -3155,7 +2943,6 @@
         "test": "mojo_public_system_unittests"
       },
       {
-        "override_isolate_target": "mojo_system_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -3169,7 +2956,6 @@
         "test": "mojo_system_unittests"
       },
       {
-        "override_isolate_target": "net_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -3182,7 +2968,6 @@
         "test": "net_unittests"
       },
       {
-        "override_isolate_target": "sandbox_linux_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -3195,7 +2980,6 @@
         "test": "sandbox_linux_unittests"
       },
       {
-        "override_isolate_target": "sql_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -3208,7 +2992,6 @@
         "test": "sql_unittests"
       },
       {
-        "override_isolate_target": "storage_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -3221,7 +3004,6 @@
         "test": "storage_unittests"
       },
       {
-        "override_isolate_target": "ui_android_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -3234,7 +3016,6 @@
         "test": "ui_android_unittests"
       },
       {
-        "override_isolate_target": "ui_base_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -3247,7 +3028,6 @@
         "test": "ui_base_unittests"
       },
       {
-        "override_isolate_target": "ui_touch_selection_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -3260,7 +3040,6 @@
         "test": "ui_touch_selection_unittests"
       },
       {
-        "override_isolate_target": "unit_tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -3273,10 +3052,6 @@
         "test": "unit_tests"
       },
       {
-        "override_compile_targets": [
-          "webview_instrumentation_test_apk"
-        ],
-        "override_isolate_target": "webview_instrumentation_test_apk",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -3298,9 +3073,6 @@
         ],
         "isolate_name": "telemetry_perf_unittests",
         "name": "telemetry_perf_unittests",
-        "override_compile_targets": [
-          "telemetry_perf_unittests"
-        ],
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
diff --git a/testing/buildbot/chromium.android.json b/testing/buildbot/chromium.android.json
index 50d1290..d6387fa 100644
--- a/testing/buildbot/chromium.android.json
+++ b/testing/buildbot/chromium.android.json
@@ -16,7 +16,6 @@
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "override_isolate_target": "android_webview_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -56,7 +55,6 @@
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "override_isolate_target": "base_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -96,7 +94,6 @@
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "override_isolate_target": "blink_heap_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -137,7 +134,6 @@
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "override_isolate_target": "breakpad_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -177,7 +173,6 @@
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "override_isolate_target": "capture_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -208,7 +203,6 @@
         "test": "capture_unittests"
       },
       {
-        "override_isolate_target": "cc_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -252,10 +246,6 @@
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "override_compile_targets": [
-          "chrome_public_test_vr_apk"
-        ],
-        "override_isolate_target": "chrome_public_test_vr_apk",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -295,10 +285,6 @@
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "override_compile_targets": [
-          "chrome_sync_shell_test_apk"
-        ],
-        "override_isolate_target": "chrome_sync_shell_test_apk",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -339,7 +325,6 @@
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "override_isolate_target": "components_browsertests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -379,7 +364,6 @@
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "override_isolate_target": "components_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -419,10 +403,6 @@
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "override_compile_targets": [
-          "content_shell_test_apk"
-        ],
-        "override_isolate_target": "content_shell_test_apk",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -463,7 +443,6 @@
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "override_isolate_target": "content_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -503,7 +482,6 @@
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "override_isolate_target": "device_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -543,7 +521,6 @@
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "override_isolate_target": "events_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -583,7 +560,6 @@
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "override_isolate_target": "gfx_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -623,7 +599,6 @@
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "override_isolate_target": "gl_tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -663,7 +638,6 @@
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "override_isolate_target": "gl_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -704,7 +678,6 @@
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "override_isolate_target": "gpu_ipc_service_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -744,7 +717,6 @@
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "override_isolate_target": "gpu_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -784,7 +756,6 @@
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "override_isolate_target": "ipc_tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -824,7 +795,6 @@
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "override_isolate_target": "latency_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -864,7 +834,6 @@
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "override_isolate_target": "media_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -904,7 +873,6 @@
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "override_isolate_target": "mojo_common_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -945,7 +913,6 @@
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "override_isolate_target": "mojo_public_bindings_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -986,7 +953,6 @@
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "override_isolate_target": "mojo_public_system_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -1027,7 +993,6 @@
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "override_isolate_target": "mojo_system_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -1068,10 +1033,6 @@
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "override_compile_targets": [
-          "mojo_test_apk"
-        ],
-        "override_isolate_target": "mojo_test_apk",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -1112,7 +1073,6 @@
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "override_isolate_target": "net_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -1152,7 +1112,6 @@
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "override_isolate_target": "sandbox_linux_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -1183,7 +1142,6 @@
         "test": "sandbox_linux_unittests"
       },
       {
-        "override_isolate_target": "service_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -1224,7 +1182,6 @@
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "override_isolate_target": "sql_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -1264,7 +1221,6 @@
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "override_isolate_target": "storage_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -1304,7 +1260,6 @@
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "override_isolate_target": "ui_android_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -1344,7 +1299,6 @@
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "override_isolate_target": "ui_base_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -1384,7 +1338,6 @@
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "override_isolate_target": "ui_touch_selection_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -1424,7 +1377,6 @@
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "override_isolate_target": "unit_tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -1464,7 +1416,6 @@
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "override_isolate_target": "vr_shell_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -1505,10 +1456,6 @@
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "override_compile_targets": [
-          "webview_instrumentation_test_apk"
-        ],
-        "override_isolate_target": "webview_instrumentation_test_apk",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -1548,9 +1495,6 @@
         ],
         "isolate_name": "telemetry_perf_unittests",
         "name": "telemetry_perf_unittests",
-        "override_compile_targets": [
-          "telemetry_perf_unittests"
-        ],
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -1587,9 +1531,6 @@
         "test": "base_unittests"
       },
       {
-        "override_compile_targets": [
-          "breakpad_unittests"
-        ],
         "test": "breakpad_unittests"
       },
       {
@@ -1644,9 +1585,6 @@
         "test": "net_unittests"
       },
       {
-        "override_compile_targets": [
-          "sandbox_linux_unittests"
-        ],
         "test": "sandbox_linux_unittests"
       },
       {
@@ -1698,7 +1636,6 @@
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "override_isolate_target": "android_webview_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -1740,7 +1677,6 @@
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "override_isolate_target": "base_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -1782,10 +1718,6 @@
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "override_compile_targets": [
-          "breakpad_unittests"
-        ],
-        "override_isolate_target": "breakpad_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -1827,7 +1759,6 @@
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "override_isolate_target": "capture_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -1860,7 +1791,6 @@
         "test": "capture_unittests"
       },
       {
-        "override_isolate_target": "cc_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -1902,7 +1832,6 @@
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "override_isolate_target": "components_browsertests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -1944,7 +1873,6 @@
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "override_isolate_target": "components_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -1986,7 +1914,6 @@
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "override_isolate_target": "content_browsertests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -2028,7 +1955,6 @@
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "override_isolate_target": "content_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -2070,7 +1996,6 @@
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "override_isolate_target": "device_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -2112,7 +2037,6 @@
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "override_isolate_target": "events_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -2154,7 +2078,6 @@
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "override_isolate_target": "gfx_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -2196,7 +2119,6 @@
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "override_isolate_target": "gl_tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -2238,7 +2160,6 @@
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "override_isolate_target": "gl_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -2280,7 +2201,6 @@
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "override_isolate_target": "gpu_ipc_service_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -2322,7 +2242,6 @@
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "override_isolate_target": "gpu_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -2364,7 +2283,6 @@
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "override_isolate_target": "ipc_tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -2406,7 +2324,6 @@
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "override_isolate_target": "latency_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -2448,7 +2365,6 @@
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "override_isolate_target": "media_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -2490,7 +2406,6 @@
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "override_isolate_target": "net_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -2532,10 +2447,6 @@
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "override_compile_targets": [
-          "sandbox_linux_unittests"
-        ],
-        "override_isolate_target": "sandbox_linux_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -2577,7 +2488,6 @@
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "override_isolate_target": "sql_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -2619,7 +2529,6 @@
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "override_isolate_target": "storage_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -2661,7 +2570,6 @@
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "override_isolate_target": "ui_android_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -2703,7 +2611,6 @@
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "override_isolate_target": "ui_base_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -2745,7 +2652,6 @@
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "override_isolate_target": "ui_touch_selection_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -2787,7 +2693,6 @@
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "override_isolate_target": "unit_tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -2829,7 +2734,6 @@
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "override_isolate_target": "vr_shell_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -2871,10 +2775,6 @@
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "override_compile_targets": [
-          "chrome_public_test_apk"
-        ],
-        "override_isolate_target": "chrome_public_test_apk",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -2920,10 +2820,6 @@
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "override_compile_targets": [
-          "chrome_public_test_vr_apk"
-        ],
-        "override_isolate_target": "chrome_public_test_vr_apk",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -2965,10 +2861,6 @@
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "override_compile_targets": [
-          "chrome_sync_shell_test_apk"
-        ],
-        "override_isolate_target": "chrome_sync_shell_test_apk",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -3010,10 +2902,6 @@
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "override_compile_targets": [
-          "content_shell_test_apk"
-        ],
-        "override_isolate_target": "content_shell_test_apk",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -3055,10 +2943,6 @@
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "override_compile_targets": [
-          "webview_instrumentation_test_apk"
-        ],
-        "override_isolate_target": "webview_instrumentation_test_apk",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -3101,9 +2985,6 @@
         "test": "base_unittests"
       },
       {
-        "override_compile_targets": [
-          "breakpad_unittests"
-        ],
         "test": "breakpad_unittests"
       },
       {
@@ -3155,9 +3036,6 @@
         "test": "net_unittests"
       },
       {
-        "override_compile_targets": [
-          "sandbox_linux_unittests"
-        ],
         "test": "sandbox_linux_unittests"
       },
       {
@@ -3209,7 +3087,6 @@
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "override_isolate_target": "android_webview_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -3249,7 +3126,6 @@
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "override_isolate_target": "base_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -3289,7 +3165,6 @@
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "override_isolate_target": "blink_heap_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -3329,7 +3204,6 @@
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "override_isolate_target": "breakpad_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -3369,7 +3243,6 @@
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "override_isolate_target": "capture_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -3400,7 +3273,6 @@
         "test": "capture_unittests"
       },
       {
-        "override_isolate_target": "cc_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -3440,10 +3312,6 @@
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "override_compile_targets": [
-          "chrome_public_test_apk"
-        ],
-        "override_isolate_target": "chrome_public_test_apk",
         "render_results_dir": "chrome/test/data/android/render_tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
@@ -3488,10 +3356,6 @@
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "override_compile_targets": [
-          "chrome_public_test_vr_apk"
-        ],
-        "override_isolate_target": "chrome_public_test_vr_apk",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -3536,10 +3400,6 @@
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
         "name": "browser_side_navigation_chrome_public_test_apk",
-        "override_compile_targets": [
-          "chrome_public_test_apk"
-        ],
-        "override_isolate_target": "chrome_public_test_apk",
         "render_results_dir": "chrome/test/data/android/render_tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
@@ -3580,10 +3440,6 @@
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "override_compile_targets": [
-          "chrome_sync_shell_test_apk"
-        ],
-        "override_isolate_target": "chrome_sync_shell_test_apk",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -3627,10 +3483,6 @@
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
         "name": "browser_side_navigation_chrome_sync_shell_test_apk",
-        "override_compile_targets": [
-          "chrome_sync_shell_test_apk"
-        ],
-        "override_isolate_target": "chrome_sync_shell_test_apk",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -3670,7 +3522,6 @@
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "override_isolate_target": "components_browsertests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -3714,7 +3565,6 @@
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
         "name": "browser_side_navigation_components_browsertests",
-        "override_isolate_target": "components_browsertests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -3754,7 +3604,6 @@
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "override_isolate_target": "components_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -3798,7 +3647,6 @@
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
         "name": "browser_side_navigation_components_unittests",
-        "override_isolate_target": "components_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -3838,7 +3686,6 @@
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "override_isolate_target": "content_browsertests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -3882,7 +3729,6 @@
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
         "name": "browser_side_navigation_content_browsertests",
-        "override_isolate_target": "content_browsertests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -3922,10 +3768,6 @@
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "override_compile_targets": [
-          "content_shell_test_apk"
-        ],
-        "override_isolate_target": "content_shell_test_apk",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -3969,10 +3811,6 @@
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
         "name": "browser_side_navigation_content_shell_test_apk",
-        "override_compile_targets": [
-          "content_shell_test_apk"
-        ],
-        "override_isolate_target": "content_shell_test_apk",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -4012,7 +3850,6 @@
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "override_isolate_target": "content_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -4056,7 +3893,6 @@
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
         "name": "browser_side_navigation_content_unittests",
-        "override_isolate_target": "content_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -4096,7 +3932,6 @@
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "override_isolate_target": "device_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -4136,7 +3971,6 @@
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "override_isolate_target": "events_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -4176,7 +4010,6 @@
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "override_isolate_target": "gfx_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -4216,7 +4049,6 @@
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "override_isolate_target": "gl_tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -4256,7 +4088,6 @@
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "override_isolate_target": "gl_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -4296,7 +4127,6 @@
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "override_isolate_target": "gpu_ipc_service_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -4336,7 +4166,6 @@
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "override_isolate_target": "gpu_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -4376,7 +4205,6 @@
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "override_isolate_target": "ipc_tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -4416,7 +4244,6 @@
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "override_isolate_target": "media_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -4456,7 +4283,6 @@
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "override_isolate_target": "net_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -4496,7 +4322,6 @@
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "override_isolate_target": "sandbox_linux_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -4536,7 +4361,6 @@
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "override_isolate_target": "sql_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -4576,7 +4400,6 @@
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "override_isolate_target": "storage_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -4616,7 +4439,6 @@
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "override_isolate_target": "ui_android_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -4656,7 +4478,6 @@
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "override_isolate_target": "ui_base_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -4696,7 +4517,6 @@
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "override_isolate_target": "ui_touch_selection_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -4736,7 +4556,6 @@
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "override_isolate_target": "unit_tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -4780,7 +4599,6 @@
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
         "name": "browser_side_navigation_unit_tests",
-        "override_isolate_target": "unit_tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -4820,7 +4638,6 @@
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "override_isolate_target": "vr_shell_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -4860,10 +4677,6 @@
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "override_compile_targets": [
-          "webview_instrumentation_test_apk"
-        ],
-        "override_isolate_target": "webview_instrumentation_test_apk",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -4907,10 +4720,6 @@
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
         "name": "browser_side_navigation_webview_instrumentation_test_apk",
-        "override_compile_targets": [
-          "webview_instrumentation_test_apk"
-        ],
-        "override_isolate_target": "webview_instrumentation_test_apk",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -4951,9 +4760,6 @@
         "test": "base_unittests"
       },
       {
-        "override_compile_targets": [
-          "breakpad_unittests"
-        ],
         "test": "breakpad_unittests"
       },
       {
@@ -5005,9 +4811,6 @@
         "test": "net_unittests"
       },
       {
-        "override_compile_targets": [
-          "sandbox_linux_unittests"
-        ],
         "test": "sandbox_linux_unittests"
       },
       {
diff --git a/testing/buildbot/chromium.fyi.json b/testing/buildbot/chromium.fyi.json
index 922cea9..988567f 100644
--- a/testing/buildbot/chromium.fyi.json
+++ b/testing/buildbot/chromium.fyi.json
@@ -233,10 +233,6 @@
           "--additional-apk=../../third_party/gvr-android-sdk/test-apks/vr_services/vr_services_current.apk"
         ],
         "name": "chrome_public_test_vr_apk-nonddready-cardboard-current-kitkat",
-        "override_compile_targets": [
-          "chrome_public_test_vr_apk"
-        ],
-        "override_isolate_target": "chrome_public_test_vr_apk",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -256,10 +252,6 @@
           "--additional-apk=../../third_party/gvr-android-sdk/test-apks/vr_services/vr_services_current.apk"
         ],
         "name": "chrome_public_test_vr_apk-nonddready-cardboard-current-lollipop",
-        "override_compile_targets": [
-          "chrome_public_test_vr_apk"
-        ],
-        "override_isolate_target": "chrome_public_test_vr_apk",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -279,10 +271,6 @@
           "--additional-apk=../../third_party/gvr-android-sdk/test-apks/vr_services/vr_services_current.apk"
         ],
         "name": "chrome_public_test_vr_apk-nonddready-cardboard-current-marshmallow",
-        "override_compile_targets": [
-          "chrome_public_test_vr_apk"
-        ],
-        "override_isolate_target": "chrome_public_test_vr_apk",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -2707,7 +2695,6 @@
   "ClangToTAndroid x64": {
     "gtest_tests": [
       {
-        "override_isolate_target": "angle_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -2720,7 +2707,6 @@
         "test": "angle_unittests"
       },
       {
-        "override_isolate_target": "base_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -2733,7 +2719,6 @@
         "test": "base_unittests"
       },
       {
-        "override_isolate_target": "blink_heap_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -2746,7 +2731,6 @@
         "test": "blink_heap_unittests"
       },
       {
-        "override_isolate_target": "breakpad_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -2759,7 +2743,6 @@
         "test": "breakpad_unittests"
       },
       {
-        "override_isolate_target": "cacheinvalidation_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -2772,7 +2755,6 @@
         "test": "cacheinvalidation_unittests"
       },
       {
-        "override_isolate_target": "capture_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -2785,7 +2767,6 @@
         "test": "capture_unittests"
       },
       {
-        "override_isolate_target": "cast_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -2798,7 +2779,6 @@
         "test": "cast_unittests"
       },
       {
-        "override_isolate_target": "cc_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -2811,10 +2791,6 @@
         "test": "cc_unittests"
       },
       {
-        "override_compile_targets": [
-          "chrome_public_test_apk"
-        ],
-        "override_isolate_target": "chrome_public_test_apk",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -2827,10 +2803,6 @@
         "test": "chrome_public_test_apk"
       },
       {
-        "override_compile_targets": [
-          "chrome_sync_shell_test_apk"
-        ],
-        "override_isolate_target": "chrome_sync_shell_test_apk",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -2843,7 +2815,6 @@
         "test": "chrome_sync_shell_test_apk"
       },
       {
-        "override_isolate_target": "components_browsertests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -2856,7 +2827,6 @@
         "test": "components_browsertests"
       },
       {
-        "override_isolate_target": "components_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -2869,7 +2839,6 @@
         "test": "components_unittests"
       },
       {
-        "override_isolate_target": "content_browsertests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -2882,10 +2851,6 @@
         "test": "content_browsertests"
       },
       {
-        "override_compile_targets": [
-          "content_shell_test_apk"
-        ],
-        "override_isolate_target": "content_shell_test_apk",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -2898,7 +2863,6 @@
         "test": "content_shell_test_apk"
       },
       {
-        "override_isolate_target": "content_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -2911,7 +2875,6 @@
         "test": "content_unittests"
       },
       {
-        "override_isolate_target": "crypto_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -2924,7 +2887,6 @@
         "test": "crypto_unittests"
       },
       {
-        "override_isolate_target": "device_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -2937,7 +2899,6 @@
         "test": "device_unittests"
       },
       {
-        "override_isolate_target": "display_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -2950,7 +2911,6 @@
         "test": "display_unittests"
       },
       {
-        "override_isolate_target": "events_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -2963,7 +2923,6 @@
         "test": "events_unittests"
       },
       {
-        "override_isolate_target": "gcm_unit_tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -2976,7 +2935,6 @@
         "test": "gcm_unit_tests"
       },
       {
-        "override_isolate_target": "gfx_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -2989,7 +2947,6 @@
         "test": "gfx_unittests"
       },
       {
-        "override_isolate_target": "gl_tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -3002,7 +2959,6 @@
         "test": "gl_tests"
       },
       {
-        "override_isolate_target": "gl_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -3015,7 +2971,6 @@
         "test": "gl_unittests"
       },
       {
-        "override_isolate_target": "google_apis_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -3028,7 +2983,6 @@
         "test": "google_apis_unittests"
       },
       {
-        "override_isolate_target": "gpu_ipc_service_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -3041,7 +2995,6 @@
         "test": "gpu_ipc_service_unittests"
       },
       {
-        "override_isolate_target": "gpu_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -3054,7 +3007,6 @@
         "test": "gpu_unittests"
       },
       {
-        "override_isolate_target": "ipc_tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -3067,7 +3019,6 @@
         "test": "ipc_tests"
       },
       {
-        "override_isolate_target": "jingle_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -3080,7 +3031,6 @@
         "test": "jingle_unittests"
       },
       {
-        "override_isolate_target": "media_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -3093,7 +3043,6 @@
         "test": "media_unittests"
       },
       {
-        "override_isolate_target": "midi_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -3106,7 +3055,6 @@
         "test": "midi_unittests"
       },
       {
-        "override_isolate_target": "mojo_common_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -3119,7 +3067,6 @@
         "test": "mojo_common_unittests"
       },
       {
-        "override_isolate_target": "mojo_public_bindings_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -3132,7 +3079,6 @@
         "test": "mojo_public_bindings_unittests"
       },
       {
-        "override_isolate_target": "mojo_public_system_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -3145,7 +3091,6 @@
         "test": "mojo_public_system_unittests"
       },
       {
-        "override_isolate_target": "mojo_system_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -3158,7 +3103,6 @@
         "test": "mojo_system_unittests"
       },
       {
-        "override_isolate_target": "net_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -3171,7 +3115,6 @@
         "test": "net_unittests"
       },
       {
-        "override_isolate_target": "remoting_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -3184,7 +3127,6 @@
         "test": "remoting_unittests"
       },
       {
-        "override_isolate_target": "sandbox_linux_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -3197,7 +3139,6 @@
         "test": "sandbox_linux_unittests"
       },
       {
-        "override_isolate_target": "skia_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -3210,7 +3151,6 @@
         "test": "skia_unittests"
       },
       {
-        "override_isolate_target": "sql_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -3223,7 +3163,6 @@
         "test": "sql_unittests"
       },
       {
-        "override_isolate_target": "storage_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -3236,7 +3175,6 @@
         "test": "storage_unittests"
       },
       {
-        "override_isolate_target": "ui_android_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -3249,7 +3187,6 @@
         "test": "ui_android_unittests"
       },
       {
-        "override_isolate_target": "ui_base_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -3262,7 +3199,6 @@
         "test": "ui_base_unittests"
       },
       {
-        "override_isolate_target": "ui_touch_selection_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -3275,7 +3211,6 @@
         "test": "ui_touch_selection_unittests"
       },
       {
-        "override_isolate_target": "unit_tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -3288,7 +3223,6 @@
         "test": "unit_tests"
       },
       {
-        "override_isolate_target": "url_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -3301,7 +3235,6 @@
         "test": "url_unittests"
       },
       {
-        "override_isolate_target": "webkit_unit_tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -3314,23 +3247,6 @@
         "test": "webkit_unit_tests"
       },
       {
-        "override_compile_targets": [
-          "webview_instrumentation_test_apk"
-        ],
-        "override_isolate_target": "webview_instrumentation_test_apk",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "android_devices": "1",
-              "device_type": "coho"
-            }
-          ]
-        },
-        "test": "webview_instrumentation_test_apk"
-      },
-      {
-        "override_isolate_target": "wtf_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -11832,7 +11748,6 @@
   "Site Isolation Android": {
     "gtest_tests": [
       {
-        "override_isolate_target": "content_browsertests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -11851,7 +11766,6 @@
           "--site-per-process"
         ],
         "name": "site_per_process_content_browsertests",
-        "override_isolate_target": "content_browsertests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -11865,7 +11779,6 @@
         "test": "content_browsertests"
       },
       {
-        "override_isolate_target": "content_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -11882,7 +11795,6 @@
           "--site-per-process"
         ],
         "name": "site_per_process_content_unittests",
-        "override_isolate_target": "content_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -11899,7 +11811,6 @@
           "--site-per-process"
         ],
         "name": "site_per_process_components_browsertests",
-        "override_isolate_target": "components_browsertests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -11916,7 +11827,6 @@
           "--site-per-process"
         ],
         "name": "site_per_process_components_unittests",
-        "override_isolate_target": "components_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
diff --git a/testing/buildbot/chromium.gpu.fyi.json b/testing/buildbot/chromium.gpu.fyi.json
index 476512ae..f499203 100644
--- a/testing/buildbot/chromium.gpu.fyi.json
+++ b/testing/buildbot/chromium.gpu.fyi.json
@@ -4,7 +4,6 @@
   "Android Release (NVIDIA Shield TV)": {
     "gtest_tests": [
       {
-        "override_isolate_target": "angle_end2end_tests",
         "swarming": {
           "can_use_on_swarming_builders": false,
           "cipd_packages": [
@@ -35,7 +34,6 @@
         "use_xvfb": false
       },
       {
-        "override_isolate_target": "angle_unittests",
         "swarming": {
           "can_use_on_swarming_builders": false,
           "cipd_packages": [
@@ -66,7 +64,6 @@
         "use_xvfb": false
       },
       {
-        "override_isolate_target": "gl_tests",
         "swarming": {
           "can_use_on_swarming_builders": false,
           "cipd_packages": [
@@ -97,7 +94,6 @@
         "use_xvfb": false
       },
       {
-        "override_isolate_target": "gl_unittests",
         "swarming": {
           "can_use_on_swarming_builders": false,
           "cipd_packages": [
@@ -398,7 +394,6 @@
   "Android Release (Nexus 5)": {
     "gtest_tests": [
       {
-        "override_isolate_target": "angle_unittests",
         "swarming": {
           "can_use_on_swarming_builders": false,
           "cipd_packages": [
@@ -429,7 +424,6 @@
         "use_xvfb": false
       },
       {
-        "override_isolate_target": "gl_tests",
         "swarming": {
           "can_use_on_swarming_builders": false,
           "cipd_packages": [
@@ -460,7 +454,6 @@
         "use_xvfb": false
       },
       {
-        "override_isolate_target": "gl_unittests",
         "swarming": {
           "can_use_on_swarming_builders": false,
           "cipd_packages": [
@@ -765,7 +758,6 @@
           "--enable-xml-result-parsing"
         ],
         "name": "angle_deqp_gles2_gles_tests",
-        "override_isolate_target": "angle_deqp_gles2_tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -802,7 +794,6 @@
           "--shard-timeout=300"
         ],
         "name": "angle_deqp_gles3_gles_tests",
-        "override_isolate_target": "angle_deqp_gles3_tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -834,7 +825,6 @@
         "use_xvfb": false
       },
       {
-        "override_isolate_target": "angle_end2end_tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -866,7 +856,6 @@
         "use_xvfb": false
       },
       {
-        "override_isolate_target": "angle_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -898,7 +887,6 @@
         "use_xvfb": false
       },
       {
-        "override_isolate_target": "gl_tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -930,7 +918,6 @@
         "use_xvfb": false
       },
       {
-        "override_isolate_target": "gl_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -1242,7 +1229,6 @@
   "Android Release (Nexus 6)": {
     "gtest_tests": [
       {
-        "override_isolate_target": "angle_unittests",
         "swarming": {
           "can_use_on_swarming_builders": false,
           "cipd_packages": [
@@ -1273,7 +1259,6 @@
         "use_xvfb": false
       },
       {
-        "override_isolate_target": "gl_tests",
         "swarming": {
           "can_use_on_swarming_builders": false,
           "cipd_packages": [
@@ -1304,7 +1289,6 @@
         "use_xvfb": false
       },
       {
-        "override_isolate_target": "gl_unittests",
         "swarming": {
           "can_use_on_swarming_builders": false,
           "cipd_packages": [
@@ -1605,7 +1589,6 @@
   "Android Release (Nexus 6P)": {
     "gtest_tests": [
       {
-        "override_isolate_target": "angle_end2end_tests",
         "swarming": {
           "can_use_on_swarming_builders": false,
           "cipd_packages": [
@@ -1636,7 +1619,6 @@
         "use_xvfb": false
       },
       {
-        "override_isolate_target": "angle_unittests",
         "swarming": {
           "can_use_on_swarming_builders": false,
           "cipd_packages": [
@@ -1667,7 +1649,6 @@
         "use_xvfb": false
       },
       {
-        "override_isolate_target": "gl_tests",
         "swarming": {
           "can_use_on_swarming_builders": false,
           "cipd_packages": [
@@ -1698,7 +1679,6 @@
         "use_xvfb": false
       },
       {
-        "override_isolate_target": "gl_unittests",
         "swarming": {
           "can_use_on_swarming_builders": false,
           "cipd_packages": [
@@ -1999,7 +1979,6 @@
   "Android Release (Nexus 9)": {
     "gtest_tests": [
       {
-        "override_isolate_target": "angle_unittests",
         "swarming": {
           "can_use_on_swarming_builders": false,
           "cipd_packages": [
@@ -2030,7 +2009,6 @@
         "use_xvfb": false
       },
       {
-        "override_isolate_target": "gl_tests",
         "swarming": {
           "can_use_on_swarming_builders": false,
           "cipd_packages": [
@@ -2061,7 +2039,6 @@
         "use_xvfb": false
       },
       {
-        "override_isolate_target": "gl_unittests",
         "swarming": {
           "can_use_on_swarming_builders": false,
           "cipd_packages": [
@@ -2362,7 +2339,6 @@
   "Android Release (Pixel C)": {
     "gtest_tests": [
       {
-        "override_isolate_target": "angle_end2end_tests",
         "swarming": {
           "can_use_on_swarming_builders": false,
           "cipd_packages": [
@@ -2393,7 +2369,6 @@
         "use_xvfb": false
       },
       {
-        "override_isolate_target": "angle_unittests",
         "swarming": {
           "can_use_on_swarming_builders": false,
           "cipd_packages": [
@@ -2424,7 +2399,6 @@
         "use_xvfb": false
       },
       {
-        "override_isolate_target": "gl_unittests",
         "swarming": {
           "can_use_on_swarming_builders": false,
           "cipd_packages": [
diff --git a/testing/buildbot/chromium.linux.json b/testing/buildbot/chromium.linux.json
index b8c172a..926074c 100644
--- a/testing/buildbot/chromium.linux.json
+++ b/testing/buildbot/chromium.linux.json
@@ -32,7 +32,6 @@
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "override_isolate_target": "android_webview_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -72,7 +71,6 @@
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "override_isolate_target": "base_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -112,7 +110,6 @@
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "override_isolate_target": "blink_heap_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -153,7 +150,6 @@
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "override_isolate_target": "boringssl_crypto_tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -193,7 +189,6 @@
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "override_isolate_target": "boringssl_ssl_tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -233,7 +228,6 @@
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "override_isolate_target": "breakpad_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -273,7 +267,6 @@
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "override_isolate_target": "capture_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -304,7 +297,6 @@
         "test": "capture_unittests"
       },
       {
-        "override_isolate_target": "cc_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -344,10 +336,6 @@
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "override_compile_targets": [
-          "chrome_public_test_apk"
-        ],
-        "override_isolate_target": "chrome_public_test_apk",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -388,10 +376,6 @@
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "override_compile_targets": [
-          "chrome_sync_shell_test_apk"
-        ],
-        "override_isolate_target": "chrome_sync_shell_test_apk",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -432,7 +416,6 @@
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "override_isolate_target": "components_browsertests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -472,7 +455,6 @@
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "override_isolate_target": "components_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -512,7 +494,6 @@
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "override_isolate_target": "content_browsertests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -553,10 +534,6 @@
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "override_compile_targets": [
-          "content_shell_test_apk"
-        ],
-        "override_isolate_target": "content_shell_test_apk",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -597,7 +574,6 @@
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "override_isolate_target": "content_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -637,7 +613,6 @@
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "override_isolate_target": "device_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -677,7 +652,6 @@
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "override_isolate_target": "events_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -717,7 +691,6 @@
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "override_isolate_target": "gl_tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -757,7 +730,6 @@
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "override_isolate_target": "gl_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -798,7 +770,6 @@
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "override_isolate_target": "gpu_ipc_service_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -838,7 +809,6 @@
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "override_isolate_target": "gpu_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -878,7 +848,6 @@
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "override_isolate_target": "ipc_tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -909,7 +878,6 @@
         "test": "ipc_tests"
       },
       {
-        "override_isolate_target": "libjingle_xmpp_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -949,7 +917,6 @@
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "override_isolate_target": "media_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -989,7 +956,6 @@
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "override_isolate_target": "mojo_common_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -1030,7 +996,6 @@
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "override_isolate_target": "mojo_public_bindings_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -1071,7 +1036,6 @@
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "override_isolate_target": "mojo_public_system_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -1112,7 +1076,6 @@
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "override_isolate_target": "mojo_system_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -1153,10 +1116,6 @@
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "override_compile_targets": [
-          "mojo_test_apk"
-        ],
-        "override_isolate_target": "mojo_test_apk",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -1197,7 +1156,6 @@
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "override_isolate_target": "net_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -1237,7 +1195,6 @@
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "override_isolate_target": "sandbox_linux_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -1277,7 +1234,6 @@
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "override_isolate_target": "sql_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -1317,7 +1273,6 @@
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "override_isolate_target": "storage_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -1357,7 +1312,6 @@
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "override_isolate_target": "ui_android_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -1397,7 +1351,6 @@
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "override_isolate_target": "ui_base_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -1437,7 +1390,6 @@
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "override_isolate_target": "ui_touch_selection_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -1477,7 +1429,6 @@
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "override_isolate_target": "unit_tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -1517,10 +1468,6 @@
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "override_compile_targets": [
-          "webview_instrumentation_test_apk"
-        ],
-        "override_isolate_target": "webview_instrumentation_test_apk",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -1561,9 +1508,6 @@
         ],
         "isolate_name": "telemetry_perf_unittests",
         "name": "telemetry_perf_unittests",
-        "override_compile_targets": [
-          "telemetry_perf_unittests"
-        ],
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -1635,7 +1579,6 @@
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "override_isolate_target": "android_webview_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -1675,7 +1618,6 @@
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "override_isolate_target": "base_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -1715,7 +1657,6 @@
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "override_isolate_target": "blink_heap_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -1756,7 +1697,6 @@
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "override_isolate_target": "boringssl_crypto_tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -1796,7 +1736,6 @@
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "override_isolate_target": "boringssl_ssl_tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -1836,7 +1775,6 @@
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "override_isolate_target": "breakpad_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -1876,7 +1814,6 @@
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "override_isolate_target": "capture_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -1907,7 +1844,6 @@
         "test": "capture_unittests"
       },
       {
-        "override_isolate_target": "cc_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -1947,10 +1883,6 @@
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "override_compile_targets": [
-          "chrome_public_test_apk"
-        ],
-        "override_isolate_target": "chrome_public_test_apk",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -1991,10 +1923,6 @@
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "override_compile_targets": [
-          "chrome_sync_shell_test_apk"
-        ],
-        "override_isolate_target": "chrome_sync_shell_test_apk",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -2035,7 +1963,6 @@
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "override_isolate_target": "components_browsertests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -2075,7 +2002,6 @@
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "override_isolate_target": "components_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -2115,7 +2041,6 @@
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "override_isolate_target": "content_browsertests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -2156,10 +2081,6 @@
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "override_compile_targets": [
-          "content_shell_test_apk"
-        ],
-        "override_isolate_target": "content_shell_test_apk",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -2200,7 +2121,6 @@
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "override_isolate_target": "content_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -2240,7 +2160,6 @@
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "override_isolate_target": "device_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -2280,7 +2199,6 @@
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "override_isolate_target": "events_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -2320,7 +2238,6 @@
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "override_isolate_target": "gl_tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -2360,7 +2277,6 @@
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "override_isolate_target": "gl_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -2401,7 +2317,6 @@
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "override_isolate_target": "gpu_ipc_service_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -2441,7 +2356,6 @@
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "override_isolate_target": "gpu_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -2481,7 +2395,6 @@
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "override_isolate_target": "ipc_tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -2512,7 +2425,6 @@
         "test": "ipc_tests"
       },
       {
-        "override_isolate_target": "libjingle_xmpp_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -2552,7 +2464,6 @@
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "override_isolate_target": "media_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -2592,7 +2503,6 @@
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "override_isolate_target": "mojo_common_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -2633,7 +2543,6 @@
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "override_isolate_target": "mojo_public_bindings_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -2674,7 +2583,6 @@
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "override_isolate_target": "mojo_public_system_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -2715,7 +2623,6 @@
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "override_isolate_target": "mojo_system_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -2756,10 +2663,6 @@
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "override_compile_targets": [
-          "mojo_test_apk"
-        ],
-        "override_isolate_target": "mojo_test_apk",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -2800,7 +2703,6 @@
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "override_isolate_target": "net_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -2840,7 +2742,6 @@
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "override_isolate_target": "sandbox_linux_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -2871,7 +2772,6 @@
         "test": "sandbox_linux_unittests"
       },
       {
-        "override_isolate_target": "service_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -2912,7 +2812,6 @@
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "override_isolate_target": "sql_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -2952,7 +2851,6 @@
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "override_isolate_target": "storage_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -2992,7 +2890,6 @@
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "override_isolate_target": "ui_android_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -3032,7 +2929,6 @@
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "override_isolate_target": "ui_base_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -3072,7 +2968,6 @@
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "override_isolate_target": "ui_touch_selection_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -3112,7 +3007,6 @@
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "override_isolate_target": "unit_tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -3152,10 +3046,6 @@
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "override_compile_targets": [
-          "webview_instrumentation_test_apk"
-        ],
-        "override_isolate_target": "webview_instrumentation_test_apk",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -3196,9 +3086,6 @@
         ],
         "isolate_name": "telemetry_perf_unittests",
         "name": "telemetry_perf_unittests",
-        "override_compile_targets": [
-          "telemetry_perf_unittests"
-        ],
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
diff --git a/testing/buildbot/chromium.swarm.json b/testing/buildbot/chromium.swarm.json
index 0aa5581..0ad7669 100644
--- a/testing/buildbot/chromium.swarm.json
+++ b/testing/buildbot/chromium.swarm.json
@@ -2,7 +2,6 @@
   "Android N5 Swarm": {
     "gtest_tests": [
       {
-        "override_isolate_target": "base_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -15,10 +14,6 @@
         "test": "base_unittests"
       },
       {
-        "override_compile_targets": [
-          "chrome_public_test_apk"
-        ],
-        "override_isolate_target": "chrome_public_test_apk",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -32,7 +27,6 @@
         "test": "chrome_public_test_apk"
       },
       {
-        "override_isolate_target": "content_browsertests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -46,7 +40,6 @@
         "test": "content_browsertests"
       },
       {
-        "override_isolate_target": "content_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -60,7 +53,6 @@
         "test": "content_unittests"
       },
       {
-        "override_isolate_target": "net_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -74,7 +66,6 @@
         "test": "net_unittests"
       },
       {
-        "override_isolate_target": "unit_tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -88,10 +79,6 @@
         "test": "unit_tests"
       },
       {
-        "override_compile_targets": [
-          "webview_instrumentation_test_apk"
-        ],
-        "override_isolate_target": "webview_instrumentation_test_apk",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -109,7 +96,6 @@
   "Android N5X Swarm": {
     "gtest_tests": [
       {
-        "override_isolate_target": "base_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -122,10 +108,6 @@
         "test": "base_unittests"
       },
       {
-        "override_compile_targets": [
-          "chrome_public_test_apk"
-        ],
-        "override_isolate_target": "chrome_public_test_apk",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -139,7 +121,6 @@
         "test": "chrome_public_test_apk"
       },
       {
-        "override_isolate_target": "content_browsertests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -153,7 +134,6 @@
         "test": "content_browsertests"
       },
       {
-        "override_isolate_target": "content_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -167,7 +147,6 @@
         "test": "content_unittests"
       },
       {
-        "override_isolate_target": "net_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -181,7 +160,6 @@
         "test": "net_unittests"
       },
       {
-        "override_isolate_target": "unit_tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -195,10 +173,6 @@
         "test": "unit_tests"
       },
       {
-        "override_compile_targets": [
-          "webview_instrumentation_test_apk"
-        ],
-        "override_isolate_target": "webview_instrumentation_test_apk",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
diff --git a/testing/buildbot/filters/ash_mus_unittests.filter b/testing/buildbot/filters/ash_mus_unittests.filter
index 7745307..0e40e99a 100644
--- a/testing/buildbot/filters/ash_mus_unittests.filter
+++ b/testing/buildbot/filters/ash_mus_unittests.filter
@@ -6,14 +6,9 @@
 -AshNativeCursorManagerTest.SetCursorSet
 -AshNativeCursorManagerTest.SetDeviceScaleFactorAndRotation
 -AshNativeCursorManagerTest.UIScaleShouldNotChangeCursor
--AshPopupAlignmentDelegateTest.Unified
 -CursorWindowControllerTest.DSF
 -CursorWindowControllerTest.MoveToDifferentDisplay
 -CursorWindowControllerTest.VisibilityTest
--DisplayManagerOrientationTest.LockToSpecificOrientation
--DisplayManagerOrientationTest.SaveRestoreUserRotationLock
--DisplayManagerOrientationTest.UserRotationLockReverse
--DisplayManagerTest.ResolutionChangeInUnifiedMode
 -DisplayManagerTest.SoftwareMirroringWithCompositingCursor
 -DisplayManagerTest.TestDeviceScaleOnlyChange
 -DisplayManagerTest.UnifiedDesktopWith2xDSF
@@ -34,7 +29,6 @@
 -DragDropControllerTest.ViewRemovedWhileInDragDropTest
 -DragDropControllerTest.WindowDestroyedDuringDragDrop
 -DragWindowResizerTest.CursorDeviceScaleFactor
--ExtendedDesktopTest.KeyEventsOnLockScreen
 -ExtendedDesktopTest.TestCursor
 -ImmersiveFullscreenControllerTest.EndRevealViaGesture
 -LaserPointerControllerTest.LaserPointerPrediction
@@ -43,10 +37,6 @@
 -LockStateControllerTest.RequestShutdownFromLockScreen
 -LockStateControllerTest.RequestShutdownFromLoginScreen
 -LockStateControllerTest.ShutdownWithoutButton
--MagnificationControllerTest.CenterTextCaretInViewport
--MagnificationControllerTest.CenterTextCaretNotInsideViewport
--MagnificationControllerTest.FollowTextInputFieldFocus
--MagnificationControllerTest.FollowTextInputFieldKeyPress
 -MagnificationControllerTest.PanWindowToLeft
 -MagnificationControllerTest.PanWindowToRight
 -MaximizeModeControllerTest.CloseLidWhileInMaximizeMode
@@ -56,7 +46,6 @@
 -MaximizeModeControllerTest.MaximizeModeAfterExitingDockedMode
 -MaximizeModeControllerTest.MaximizeModeTest
 -MaximizeModeControllerTest.NoMaximizeModeWithDisabledInternalDisplay
--MaximizeModeControllerTest.RestoreAfterExit
 -MaximizeModeControllerTest.StableHingeAnglesWithLidOpened
 -MaximizeModeControllerTest.TabletModeTransition
 -MaximizeModeControllerTest.TabletModeTransitionNoKeyboardAccelerometer
@@ -85,32 +74,19 @@
 -ResizeShadowAndCursorTest.MaximizeRestore
 -ResizeShadowAndCursorTest.MouseDrag
 -ResizeShadowAndCursorTest.MouseHover
--RootWindowControllerTest.MoveWindows_LockWindowsInUnified
--ScreenLayoutObserverTest.AddingRemovingDisplayExtendedModeMessage
--ScreenLayoutObserverTest.DisplayConfigurationChangedTwice
--ScreenLayoutObserverTest.DisplayNotifications
--ScreenLayoutObserverTest.DockedModeWithExternalPrimaryDisplayMessage
--ScreenLayoutObserverTest.EnteringExitingUnifiedModeMessage
--ScreenLayoutObserverTest.ExitMirrorModeBecauseOfDockedModeMessage
--ScreenLayoutObserverTest.ExitMirrorModeBecauseOfThirdDisplayMessage
--ScreenLayoutObserverTest.ExitMirrorModeNoInternalDisplayBecauseOfDisplayRemovedMessage
--ScreenLayoutObserverTest.RotationNotification
--ScreenLayoutObserverTest.UpdateAfterSuppressDisplayNotification
+-ScreenshotControllerTest.BreaksCapture
+-ScreenshotControllerTest.MultipleDisplays
 -ScreenRotationAnimatorSmoothAnimationTest.RotatesToDifferentRotationWithCopyCallback
 -ScreenRotationAnimatorSmoothAnimationTest.RemoveExternalSecondaryDisplayBeforeSecondCopyCallback
 -ScreenRotationAnimatorSmoothAnimationTest.RemoveExternalPrimaryDisplayBeforeSecondCopyCallback
--ScreenUtilTest.ShelfDisplayBoundsInUnifiedDesktop
--ScreenshotControllerTest.BreaksCapture
--ScreenshotControllerTest.MultipleDisplays
--ShelfLayoutManagerTest.ShelfLayoutInUnifiedDesktop
 -ShellTest2.DontCrashWhenWindowDeleted
+-ToastManagerTest.NullMessageHasNoDismissButton
 -ToastManagerTest.QueueMessage
 -ToastManagerTest.ShowAndCloseManuallyDuringAnimation
 -TooltipControllerTest.HideTooltipWhenCursorHidden
 -ToplevelWindowEventHandlerTest.GestureDragCaptureLoss
 -TrayIMETest.HidesOnA11yEnabled
 -TrayIMETest.PerformActionOnDetailedView
--UnifiedMouseWarpControllerTest.BoundaryTest
 -UnifiedMouseWarpControllerTest.WarpMouse
 -VirtualKeyboardControllerAlwaysEnabledTest.DoesNotSuppressKeyboard
 -VirtualKeyboardControllerAutoTest.DisabledIfInternalKeyboardPresent
@@ -121,13 +97,11 @@
 -VirtualKeyboardControllerAutoTest.SuppressedInMaximizedMode
 -VirtualKeyboardControllerTest.EnabledDuringMaximizeMode
 -VirtualKeyboardControllerTest.RestoreKeyboardDevices
--WallpaperControllerTest.GetMaxDisplaySize
--WebNotificationTrayTest.PopupShownOnBothDisplays
 -WindowManagerTest.MouseEventCursors
 -WindowManagerTest.TestCursorClientObserver
 -WindowManagerTest.UpdateCursorVisibility
--WindowManagerTest.UpdateCursorVisibilityOnKeyEvent
 -WindowManagerTest.UpdateCursorVisibilityAccelerator
+-WindowManagerTest.UpdateCursorVisibilityOnKeyEvent
 -WindowScreenshotControllerTest.KeyboardOperation
 -WindowScreenshotControllerTest.MouseOperation
 -WindowScreenshotControllerTest.MultiDisplays
diff --git a/third_party/WebKit/LayoutTests/FlagExpectations/enable-slimming-paint-v2 b/third_party/WebKit/LayoutTests/FlagExpectations/enable-slimming-paint-v2
index d4483dd..a94af95e 100644
--- a/third_party/WebKit/LayoutTests/FlagExpectations/enable-slimming-paint-v2
+++ b/third_party/WebKit/LayoutTests/FlagExpectations/enable-slimming-paint-v2
@@ -107,6 +107,17 @@
 Bug(none) virtual/windows-directwrite/ [ Skip ]
 Bug(none) virtual/without-smil/ [ Skip ]
 
+Bug(none) paint/transparency/compositing-alpha-fold-crash.html [ Failure ]
+Bug(none) paint/invalidation/table/row-change-background-rowspan-cell.html [ Failure ]
+Bug(none) virtual/new-remote-playback-pipeline/media/controls/video-controls-with-cast-rendering.html [ Failure ]
+Bug(none) virtual/new-remote-playback-pipeline/media/controls/video-overlay-cast-dark-rendering.html [ Failure ]
+Bug(none) paint/invalidation/obscured-background-no-repaint.html [ Crash ]
+Bug(none) paint/invalidation/compositing/newly-composited-repaint-rect.html [ Failure ]
+Bug(none) virtual/new-remote-playback-pipeline/media/controls/video-overlay-cast-light-rendering.html [ Failure ]
+Bug(none) svg/foreignObject/overflow-clip-in-hidden-container-crash.html [ Crash ]
+Bug(none) images/rendering-broken-0px-images.html [ Failure ]
+Bug(none) images/rendering-broken-0px-images-quirk.html [ Failure ]
+Bug(none) paint/invalidation/overflow-hidden-to-visible.html [ Failure ]
 Bug(none) compositing/3d-cube.html [ Failure ]
 Bug(none) compositing/absolute-inside-out-of-view-fixed.html [ Failure ]
 Bug(none) compositing/animation/hidden-composited.html [ Failure ]
@@ -1424,7 +1435,6 @@
 Bug(none) paint/invalidation/overflow-flipped-writing-mode-block.html [ Failure ]
 Bug(none) paint/invalidation/overflow-flipped-writing-mode-table.html [ Failure ]
 Bug(none) paint/invalidation/overflow-hidden-in-overflow-hidden-scrolled.html [ Failure ]
-Bug(none) paint/invalidation/overflow-hidden-to-visible.html [ Failure ]
 Bug(none) paint/invalidation/overflow-hidden-yet-scrolled-with-custom-scrollbar.html [ Failure ]
 Bug(none) paint/invalidation/overflow-hidden-yet-scrolled.html [ Failure ]
 Bug(none) paint/invalidation/overflow-hide.html [ Failure ]
@@ -1724,7 +1734,6 @@
 Bug(none) paint/invalidation/table/resize-table-repaint-percent-size-cell.html [ Failure ]
 Bug(none) paint/invalidation/table/resize-table-repaint-vertical-align-cell.html [ Failure ]
 Bug(none) paint/invalidation/table/resize-table-row-repaint.html [ Failure ]
-Bug(none) paint/invalidation/table/row-change-background-rowspan-cell.html [ Failure ]
 Bug(none) paint/invalidation/text-append-dirty-lines.html [ Failure ]
 Bug(none) paint/invalidation/text-in-relative-positioned-inline.html [ Failure ]
 Bug(none) paint/invalidation/text-match-document-change.html [ Failure ]
@@ -1776,7 +1785,6 @@
 Bug(none) paint/pagination/pagination-change-clip-crash.html [ Failure ]
 Bug(none) paint/selection/text-selection-newline-mixed-ltr-rtl.html [ Failure ]
 Bug(none) paint/selection/text-selection-newline-rtl-double-linebreak.html [ Failure ]
-Bug(none) paint/transparency/compositing-alpha-fold-crash.html [ Failure ]
 Bug(none) svg/as-background-image/tiled-background-image.html [ Crash Timeout ]
 # Mask does not work correctly
 crbug.com/707444 svg/as-background-image/svg-as-background-6.html [ Failure Crash ]
diff --git a/third_party/WebKit/LayoutTests/PRESUBMIT.py b/third_party/WebKit/LayoutTests/PRESUBMIT.py
index 1f2e4f3..38e68f0 100644
--- a/third_party/WebKit/LayoutTests/PRESUBMIT.py
+++ b/third_party/WebKit/LayoutTests/PRESUBMIT.py
@@ -97,7 +97,7 @@
         if f.Action() == 'A':
             for line_num, line in f.ChangedContents():
                 if any(action in line for action in actions):
-                    results.append(output_api.PresubmitError(
+                    results.append(output_api.PresubmitPromptWarning(
                         'eventSender is deprecated, please use chrome.gpuBenchmarking.pointerActionSequence instead ' +
                         '(see https://crbug.com/711340 and http://goo.gl/BND75q).\n' +
                         'Files: %s:%d %s ' % (f.LocalPath(), line_num, line)))
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations
index e71d63f4..9cb55a6 100644
--- a/third_party/WebKit/LayoutTests/TestExpectations
+++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -125,6 +125,9 @@
 crbug.com/717389 [ Win7 Debug ] virtual/gpu/fast/canvas/canvas-clip-rule.html [ Timeout ]
 crbug.com/717389 [ Win7 Debug ] virtual/gpu/fast/canvas/canvas-path-context-clip.html [ Timeout ]
 
+# This test fails only when spv2 is enabled.
+crbug.com/719533 compositing/overflow/absolute-element-in-isolated-composited-ancestor.html [ Failure ]
+
 # ====== Paint team owned tests to here ======
 
 # ====== Layout team owned tests from here ======
@@ -2010,9 +2013,6 @@
 # Temporary, until we stop use_system_harfbuzz on Linux including non-official builds
 crbug.com/462689 [ Linux ] fast/text/unicode-variation-selector.html [ Failure ]
 
-# Temporary, until WebAXObjectProxy support lands.
-crbug.com/421771 accessibility/inline-text-box-next-on-line.html [ Skip ]
-
 # Disabled briefly until test runner support lands.
 crbug.com/479533 accessibility/show-context-menu.html [ Skip ]
 crbug.com/479533 accessibility/show-context-menu-shadowdom.html [ Skip ]
diff --git a/third_party/WebKit/LayoutTests/accessibility/inline-text-box-next-on-line.html b/third_party/WebKit/LayoutTests/accessibility/inline-text-box-next-on-line.html
index b16feff..779dd70 100644
--- a/third_party/WebKit/LayoutTests/accessibility/inline-text-box-next-on-line.html
+++ b/third_party/WebKit/LayoutTests/accessibility/inline-text-box-next-on-line.html
@@ -3,118 +3,143 @@
 <script src="../resources/testharnessreport.js"></script>
 
 <p id="paragraph">
-The <b id="quick">quick</b> brown fox
-<br>
-jumps over the lazy <b id="dog">dog</b>.
+  The <b id="quick">quick</b> brown fox
+  <br>
+  jumps over the lazy <b id="dog">dog</b>.
 </p>
 
 <div contentEditable="true" id="contentEditable">
-    <div>
-        <span>Line </span><span>one has one trailing space.</span><span> </span>
-    </div>
-    <div>
-        <span>&#9;&#9;</span><span>Line</span><span> two has two leading tabs.</span>
-    </div>
+  <div>
+    <span>Line </span><span>one has one trailing space.</span><span> </span>
+  </div>
+  <div>
+    <span>&#9;&#9;</span><span>Line</span><span> two has two leading tabs.</span>
+  </div>
 </div>
 
 <p id="paragraphWithLink">
-    Paragraph with <a href="#">link</a>
+  Paragraph with <a href="#">link</a>
 </p>
 
+<ol id="list">
+  <li>List item</li>
+</ol>
+
 <script>
-test(function(t)
-{
-    var axObj = accessibilityController.accessibleElementById('paragraph');
-    // Find the first inline text box.
-    while (axObj.childrenCount > 0)
-        axObj = axObj.childAtIndex(0);
-    assert_equals(axObj.role, 'AXRole: AXInlineTextBox');
-
-    var lineText = [];
-    var lastInlineText = axObj;
-    while (axObj && axObj.isValid) {
-        assert_equals(axObj.role, 'AXRole: AXInlineTextBox');
-        lineText.push(axObj.name.replace('AXValue: ', ''));
-        lastInlineText = axObj;
-        axObj = axObj.nextOnLine();
-    }
-    assert_array_equals(lineText, ['The ', 'quick', ' brown fox ', '\n']);
-
-    // Now walk backwards.
-    lineText = [];
-    axObj = lastInlineText;
-    while (axObj && axObj.isValid) {
-        assert_equals(axObj.role, 'AXRole: AXInlineTextBox');
-        lineText.unshift(axObj.name.replace('AXValue: ', ''));
-        axObj = axObj.previousOnLine();
-    }
-    assert_array_equals(lineText, ['The ', 'quick', ' brown fox ', '\n']);
-}, 'Test |nextOnLine| and |previousOnLine| for |AXInlineTextBox|.');
-
-test(function(t)
-{
-    var axEditable = accessibilityController.accessibleElementById('contentEditable');
-    // There should be two lines in this content editable.
-    assert_equals(axEditable.childrenCount, 2);
-    var lines = [axEditable.childAtIndex(0), axEditable.childAtIndex(1)];
-    var lineText = [
-      ['Line ', 'one has one trailing space.'],
-      ['Line', ' two has two leading tabs.']];
-
-    for (var i = 0; i < lines.length; ++i) {
-        var currentLine = lines[i];
-        assert_equals(currentLine.nextOnLine(), undefined);
-        assert_equals(currentLine.previousOnLine(), undefined);
-    }
-
-    for (var i = 0; i < lines.length; ++i) {
-        var currentLine = lines[i];
-        var currentLineText = lineText[i];
-        // There should be two spans per line since white space is removed.
-        assert_equals(currentLine.childrenCount, 2);
-
-        var span1 = currentLine.childAtIndex(0);
-        var span2 = currentLine.childAtIndex(1);
-        var inlineText1 = span1.childAtIndex(0);
-        var inlineText2 = span2.childAtIndex(0);
-        var spanText1 = currentLineText[0];
-        var spanText2 = currentLineText[1];
-        assert_equals(span1.role, 'AXRole: AXStaticText');
-        assert_equals(span2.role, 'AXRole: AXStaticText');
-        assert_equals(span1.name, spanText1);
-        assert_equals(span2.name, spanText2);
-
-        // |next/previousOnLine| APIs jump directly to the inline text boxes
-        // skipping the parent span element.
-        assert_equals(span1.nextOnLine(), inlineText2, 'span1 -> inlineText2');
-        assert_equals(inlineText1.nextOnLine(), inlineText2, 'inlineText1 -> inlineText2');
-        assert_equals(span2.previousOnLine(), inlineText1, 'span2 -> inlineText1');
-        assert_equals(inlineText2.previousOnLine(), inlineText1, 'inlineText2 -> inlineText1');
-    }
-}, 'Test |nextOnLine| and |previousOnLine| for |AXLayoutObject|.');
-
-test(function(t)
-{
-    var axObj = accessibilityController.accessibleElementById('paragraphWithLink');
-    // There should be one static text child and a link in this paragraph.
-    assert_equals(axObj.childrenCount, 2);
+test(function(t) {
+  var axObj = accessibilityController.accessibleElementById('paragraph');
+  // Find the first inline text box.
+  while (axObj.childrenCount > 0)
     axObj = axObj.childAtIndex(0);
-    assert_equals(axObj.role, 'AXRole: AXStaticText');
+  assert_equals(axObj.role, 'AXRole: AXInlineTextBox');
 
-    var lineText = [];
-    lineText.push(axObj.name);
+  var lineText = [];
+  var lastInlineText = axObj;
+  while (axObj && axObj.isValid) {
+    assert_equals(axObj.role, 'AXRole: AXInlineTextBox');
+    lineText.push(axObj.name.replace('AXValue: ', ''));
+    lastInlineText = axObj;
     axObj = axObj.nextOnLine();
+  }
+  assert_array_equals(lineText, ['The ', 'quick', ' brown fox ']);
+
+  // Now walk backwards.
+  lineText = [];
+  axObj = lastInlineText;
+  while (axObj && axObj.isValid) {
     assert_equals(axObj.role, 'AXRole: AXInlineTextBox');
-    lineText.push(axObj.name);
+    lineText.unshift(axObj.name.replace('AXValue: ', ''));
     axObj = axObj.previousOnLine();
-    assert_equals(axObj.role, 'AXRole: AXInlineTextBox');
-    lineText.push(axObj.name);
-    assert_array_equals(lineText, ['Paragraph with ', 'link', 'Paragraph with ']);
-}, 'Test |nextOnLine| and |previousOnLine| for paragraphs with links.');
+  }
+  assert_array_equals(lineText, ['The ', 'quick', ' brown fox ']);
+}, 'Test |NextOnLine| and |PreviousOnLine| on |AXInlineTextBox|.');
+
+test(function(t) {
+  var axEditable = accessibilityController.accessibleElementById('contentEditable');
+  // There should be two lines in this content editable.
+  assert_equals(axEditable.childrenCount, 2);
+  var lines = [axEditable.childAtIndex(0), axEditable.childAtIndex(1)];
+  var lineText = [
+    ['Line ', 'one has one trailing space.'],
+    ['Line', ' two has two leading tabs.']
+  ];
+
+  for (var i = 0; i < lines.length; ++i) {
+    var currentLine = lines[i];
+    assert_equals(currentLine.nextOnLine(), undefined);
+    assert_equals(currentLine.previousOnLine(), undefined);
+  }
+
+  for (var i = 0; i < lines.length; ++i) {
+    var currentLine = lines[i];
+    var currentLineText = lineText[i];
+    // There should be two spans per line since white space is removed.
+    assert_equals(currentLine.childrenCount, 2);
+
+    var span1 = currentLine.childAtIndex(0);
+    var span2 = currentLine.childAtIndex(1);
+    var inlineText1 = span1.childAtIndex(0);
+    var inlineText2 = span2.childAtIndex(0);
+    var spanText1 = currentLineText[0];
+    var spanText2 = currentLineText[1];
+    assert_equals(span1.role, 'AXRole: AXStaticText');
+    assert_equals(span2.role, 'AXRole: AXStaticText');
+    assert_equals(span1.name, spanText1);
+    assert_equals(span2.name, spanText2);
+
+    // |next/previousOnLine| APIs jump directly to the inline text boxes
+    // skipping the parent span element.
+    assert_equals(span1.nextOnLine(), inlineText2, 'span1 -> inlineText2');
+    assert_equals(inlineText1.nextOnLine(), inlineText2, 'inlineText1 -> inlineText2');
+    assert_equals(span2.previousOnLine(), inlineText1, 'span2 -> inlineText1');
+    assert_equals(inlineText2.previousOnLine(), inlineText1, 'inlineText2 -> inlineText1');
+  }
+}, 'Test |NextOnLine| and |PreviousOnLine| on |AXLayoutObject|.');
+
+test(function(t) {
+  var axObj = accessibilityController.accessibleElementById('paragraphWithLink');
+  // There should be one static text child and a link in this paragraph.
+  assert_equals(axObj.childrenCount, 2);
+  axObj = axObj.childAtIndex(0);
+  assert_equals(axObj.role, 'AXRole: AXStaticText');
+
+  var lineText = [];
+  lineText.push(axObj.name);
+  axObj = axObj.nextOnLine();
+  assert_equals(axObj.role, 'AXRole: AXInlineTextBox');
+  lineText.push(axObj.name);
+  axObj = axObj.previousOnLine();
+  assert_equals(axObj.role, 'AXRole: AXInlineTextBox');
+  lineText.push(axObj.name);
+  assert_array_equals(lineText, ['Paragraph with ', 'link', 'Paragraph with ']);
+}, 'Test |NextOnLine| and |PreviousOnLine| on paragraphs with links.');
+
+test(function(t) {
+  var axObj = accessibilityController.accessibleElementById('list');
+  // There should be a list item in this list.
+  assert_equals(axObj.childrenCount, 1);
+  axObj = axObj.childAtIndex(0);
+  assert_equals(axObj.role, 'AXRole: AXListItem');
+  // There should be a list marker and some text in this list item.
+  assert_equals(axObj.childrenCount, 2);
+  axObj = axObj.childAtIndex(0);
+  assert_equals(axObj.role, 'AXRole: AXListMarker');
+
+  var lineText = [];
+  lineText.push(axObj.name);
+  axObj = axObj.nextOnLine();
+  assert_equals(axObj.role, 'AXRole: AXInlineTextBox');
+  lineText.push(axObj.name);
+  axObj = axObj.previousOnLine();
+  assert_equals(axObj.role, 'AXRole: AXListMarker');
+  lineText.push(axObj.name);
+  assert_array_equals(lineText, ['1', 'List item', '1']);
+}, 'Test |NextOnLine| and |PreviousOnLine| on list markers.');
 
 if (window.testRunner) {
-    document.getElementById('paragraph').style.display = 'none';
-    document.getElementById('contentEditable').style.display = 'none';
-    document.getElementById('paragraphWithLink').style.display = 'none';
+  document.getElementById('paragraph').style.display = 'none';
+  document.getElementById('contentEditable').style.display = 'none';
+  document.getElementById('paragraphWithLink').style.display = 'none';
+  document.getElementById('list').style.display = 'none';
 }
 </script>
diff --git a/third_party/WebKit/LayoutTests/bluetooth/idl/idl-BluetoothDevice.html b/third_party/WebKit/LayoutTests/bluetooth/idl/idl-BluetoothDevice.html
index 42a2dcc..0e6c795 100644
--- a/third_party/WebKit/LayoutTests/bluetooth/idl/idl-BluetoothDevice.html
+++ b/third_party/WebKit/LayoutTests/bluetooth/idl/idl-BluetoothDevice.html
@@ -2,6 +2,8 @@
 <script src="../../resources/testharness.js"></script>
 <script src="../../resources/testharnessreport.js"></script>
 <script src="../../resources/bluetooth/bluetooth-helpers.js"></script>
+<script src="../../resources/bluetooth/web-bluetooth-test.js"></script>
+<script src="../../resources/mojo-helpers.js"></script>
 <script>
 test(() => {
   assert_throws(null, () => new BluetoothDevice(),
@@ -11,7 +13,7 @@
 }, 'BluetoothDevice IDL test');
 
 promise_test(() => {
-  return setBluetoothFakeAdapter('GlucoseHeartRateAdapter')
+  return setUpHealthThermometerAndHeartRateDevices()
     .then(() => requestDeviceWithKeyDown({
       filters: [{services: ['heart_rate']}]}))
     .then(device => {
@@ -23,7 +25,7 @@
       device.id = 'overwritten';
       device.name = 'overwritten';
       assert_equals(device.id, old_device_id);
-      assert_equals(device.name, 'Heart Rate Device');
+      assert_equals(device.name, 'Heart Rate');
     });
 }, 'BluetoothDevice attributes.');
 </script>
diff --git a/third_party/WebKit/LayoutTests/bluetooth/requestDevice/acceptAllDevices/device-with-empty-name.html b/third_party/WebKit/LayoutTests/bluetooth/requestDevice/acceptAllDevices/device-with-empty-name.html
index d64507d..b64594f9 100644
--- a/third_party/WebKit/LayoutTests/bluetooth/requestDevice/acceptAllDevices/device-with-empty-name.html
+++ b/third_party/WebKit/LayoutTests/bluetooth/requestDevice/acceptAllDevices/device-with-empty-name.html
@@ -2,10 +2,12 @@
 <script src="../../../resources/testharness.js"></script>
 <script src="../../../resources/testharnessreport.js"></script>
 <script src="../../../resources/bluetooth/bluetooth-helpers.js"></script>
+<script src="../../../resources/mojo-helpers.js"></script>
+<script src="../../../resources/bluetooth/web-bluetooth-test.js"></script>
 <script>
 'use strict';
 promise_test(() => {
-  return setBluetoothFakeAdapter('EmptyNameDeviceAdapter')
+  return setUpPreconnectedDevice({name: ''})
     .then(() => requestDeviceWithKeyDown({acceptAllDevices: true}))
     .then(device => {
       assert_equals(device.name, '');
diff --git a/third_party/WebKit/LayoutTests/bluetooth/requestDevice/acceptAllDevices/device-with-name.html b/third_party/WebKit/LayoutTests/bluetooth/requestDevice/acceptAllDevices/device-with-name.html
index f1241544..91e2ca4 100644
--- a/third_party/WebKit/LayoutTests/bluetooth/requestDevice/acceptAllDevices/device-with-name.html
+++ b/third_party/WebKit/LayoutTests/bluetooth/requestDevice/acceptAllDevices/device-with-name.html
@@ -2,11 +2,12 @@
 <script src="../../../resources/testharness.js"></script>
 <script src="../../../resources/testharnessreport.js"></script>
 <script src="../../../resources/bluetooth/bluetooth-helpers.js"></script>
+<script src="../../../resources/mojo-helpers.js"></script>
+<script src="../../../resources/bluetooth/web-bluetooth-test.js"></script>
 <script>
 promise_test(() => {
-  // The UnicodeDevice's name is '❤❤❤❤❤❤❤❤❤'. ❤ = \u2764
-  let device_name = generate_string(9, '\u2764');
-  return setBluetoothFakeAdapter('UnicodeDeviceAdapter')
+  let device_name = 'LE Device';
+  return setUpPreconnectedDevice({name: device_name})
     .then(() => requestDeviceWithKeyDown({acceptAllDevices: true}))
     .then(device => {
       assert_equals(device.name, device_name);
diff --git a/third_party/WebKit/LayoutTests/bluetooth/requestDevice/blocklisted-service-in-filter.html b/third_party/WebKit/LayoutTests/bluetooth/requestDevice/blocklisted-service-in-filter.html
index e203213..842f01b 100644
--- a/third_party/WebKit/LayoutTests/bluetooth/requestDevice/blocklisted-service-in-filter.html
+++ b/third_party/WebKit/LayoutTests/bluetooth/requestDevice/blocklisted-service-in-filter.html
@@ -2,10 +2,13 @@
 <script src="../../resources/testharness.js"></script>
 <script src="../../resources/testharnessreport.js"></script>
 <script src="../../resources/bluetooth/bluetooth-helpers.js"></script>
+<script src="../../resources/bluetooth/web-bluetooth-test.js"></script>
+<script src="../../resources/mojo-helpers.js"></script>
 <script>
 'use strict';
 promise_test(() => {
-  return setBluetoothFakeAdapter('BlocklistTestAdapter')
+  return setUpPreconnectedDevice({
+    knownServiceUUIDs: ['human_interface_device']})
     .then(() => assert_promise_rejects_with_message(
       requestDeviceWithKeyDown({
         filters: [{services: ['human_interface_device']}]}),
diff --git a/third_party/WebKit/LayoutTests/bluetooth/requestDevice/canonicalizeFilter/device-name-longer-than-29-bytes.html b/third_party/WebKit/LayoutTests/bluetooth/requestDevice/canonicalizeFilter/device-name-longer-than-29-bytes.html
index 1132bcc..92426f6 100644
--- a/third_party/WebKit/LayoutTests/bluetooth/requestDevice/canonicalizeFilter/device-name-longer-than-29-bytes.html
+++ b/third_party/WebKit/LayoutTests/bluetooth/requestDevice/canonicalizeFilter/device-name-longer-than-29-bytes.html
@@ -2,12 +2,14 @@
 <script src="../../../resources/testharness.js"></script>
 <script src="../../../resources/testharnessreport.js"></script>
 <script src="../../../resources/bluetooth/bluetooth-helpers.js"></script>
+<script src="../../../resources/mojo-helpers.js"></script>
+<script src="../../../resources/bluetooth/web-bluetooth-test.js"></script>
 <script>
 'use strict';
 promise_test(() => {
   const DEVICE_NAME = 'a_device_name_that_is_longer_than_29_bytes_but_shorter_than_248_bytes';
 
-  return setBluetoothFakeAdapter('DeviceNameLongerThan29BytesAdapter')
+  return setUpPreconnectedDevice({name: DEVICE_NAME})
     .then(() => requestDeviceWithKeyDown({ filters: [{name: DEVICE_NAME}]}))
     .then(device => assert_equals(device.name, DEVICE_NAME));
 }, 'A device name between 29 and 248 bytes is valid.');
diff --git a/third_party/WebKit/LayoutTests/bluetooth/requestDevice/canonicalizeFilter/unicode-valid-length-name-name.html b/third_party/WebKit/LayoutTests/bluetooth/requestDevice/canonicalizeFilter/unicode-valid-length-name-name.html
index e353123..2ed5424d 100644
--- a/third_party/WebKit/LayoutTests/bluetooth/requestDevice/canonicalizeFilter/unicode-valid-length-name-name.html
+++ b/third_party/WebKit/LayoutTests/bluetooth/requestDevice/canonicalizeFilter/unicode-valid-length-name-name.html
@@ -2,12 +2,14 @@
 <script src="../../../resources/testharness.js"></script>
 <script src="../../../resources/testharnessreport.js"></script>
 <script src="../../../resources/bluetooth/bluetooth-helpers.js"></script>
+<script src="../../../resources/mojo-helpers.js"></script>
+<script src="../../../resources/bluetooth/web-bluetooth-test.js"></script>
 <script>
 promise_test(() => {
   let valid_unicode_name = generate_string(
     9, '\u2764'); // \u2764's UTF-8 representation is 3 bytes long.
                   // 9 chars * 3 bytes/char = 27 bytes
-  return setBluetoothFakeAdapter('UnicodeDeviceAdapter')
+  return setUpPreconnectedDevice({name: valid_unicode_name})
     .then(() => requestDeviceWithKeyDown({
       filters: [{name: valid_unicode_name}]}))
     .then(device => {
diff --git a/third_party/WebKit/LayoutTests/bluetooth/requestDevice/canonicalizeFilter/unicode-valid-length-name-namePrefix.html b/third_party/WebKit/LayoutTests/bluetooth/requestDevice/canonicalizeFilter/unicode-valid-length-name-namePrefix.html
index 96dfe48..c9ea988d 100644
--- a/third_party/WebKit/LayoutTests/bluetooth/requestDevice/canonicalizeFilter/unicode-valid-length-name-namePrefix.html
+++ b/third_party/WebKit/LayoutTests/bluetooth/requestDevice/canonicalizeFilter/unicode-valid-length-name-namePrefix.html
@@ -2,12 +2,14 @@
 <script src="../../../resources/testharness.js"></script>
 <script src="../../../resources/testharnessreport.js"></script>
 <script src="../../../resources/bluetooth/bluetooth-helpers.js"></script>
+<script src="../../../resources/mojo-helpers.js"></script>
+<script src="../../../resources/bluetooth/web-bluetooth-test.js"></script>
 <script>
 promise_test(() => {
   let valid_unicode_name = generate_string(
     9, '\u2764'); // \u2764's UTF-8 representation is 3 bytes long.
                   // 9 chars * 3 bytes/char = 27 bytes
-  return setBluetoothFakeAdapter('UnicodeDeviceAdapter')
+  return setUpPreconnectedDevice({name: valid_unicode_name})
     .then(() => requestDeviceWithKeyDown({
       filters: [{namePrefix: valid_unicode_name}]}))
     .then(device => {
diff --git a/third_party/WebKit/LayoutTests/bluetooth/requestDevice/consumes-user-gesture.html b/third_party/WebKit/LayoutTests/bluetooth/requestDevice/consumes-user-gesture.html
index 5a2fd8f2..33ff28f 100644
--- a/third_party/WebKit/LayoutTests/bluetooth/requestDevice/consumes-user-gesture.html
+++ b/third_party/WebKit/LayoutTests/bluetooth/requestDevice/consumes-user-gesture.html
@@ -2,10 +2,12 @@
 <script src="../../resources/testharness.js"></script>
 <script src="../../resources/testharnessreport.js"></script>
 <script src="../../resources/bluetooth/bluetooth-helpers.js"></script>
+<script src="../../resources/bluetooth/web-bluetooth-test.js"></script>
+<script src="../../resources/mojo-helpers.js"></script>
 <script>
 'use strict';
 promise_test(t => {
-  return setBluetoothFakeAdapter('HeartRateAdapter')
+  return setUpHealthThermometerAndHeartRateDevices()
     .then(() => callWithKeyDown(() => {
       var first = navigator.bluetooth.requestDevice({
         filters: [{services: ['heart_rate']}]});
diff --git a/third_party/WebKit/LayoutTests/bluetooth/requestDevice/name-empty-device-from-name-empty-filter.html b/third_party/WebKit/LayoutTests/bluetooth/requestDevice/name-empty-device-from-name-empty-filter.html
index bf2bfbd..8e417f0c 100644
--- a/third_party/WebKit/LayoutTests/bluetooth/requestDevice/name-empty-device-from-name-empty-filter.html
+++ b/third_party/WebKit/LayoutTests/bluetooth/requestDevice/name-empty-device-from-name-empty-filter.html
@@ -2,16 +2,15 @@
 <script src="../../resources/testharness.js"></script>
 <script src="../../resources/testharnessreport.js"></script>
 <script src="../../resources/bluetooth/bluetooth-helpers.js"></script>
+<script src="../../resources/mojo-helpers.js"></script>
+<script src="../../resources/bluetooth/web-bluetooth-test.js"></script>
 <script>
 'use strict';
 promise_test(() => {
-  return setBluetoothFakeAdapter('EmptyNameHeartRateAdapter')
-  .then(() => requestDeviceWithKeyDown({
-     filters: [{name: ''}],
-     optionalServices: ['generic_access']}))
-  .then(device => {
-    assert_equals(device.name, '');
-  })
+  return setUpPreconnectedDevice({name: ''})
+    .then(() => requestDeviceWithKeyDown({filters: [{name: ''}]}))
+    .then(device => {
+      assert_equals(device.name, '');
+    });
 }, 'An empty name device can be obtained by empty name filter.');
 </script>
-
diff --git a/third_party/WebKit/LayoutTests/bluetooth/requestDevice/not-processing-user-gesture.html b/third_party/WebKit/LayoutTests/bluetooth/requestDevice/not-processing-user-gesture.html
index 908763cd..4eab362e 100644
--- a/third_party/WebKit/LayoutTests/bluetooth/requestDevice/not-processing-user-gesture.html
+++ b/third_party/WebKit/LayoutTests/bluetooth/requestDevice/not-processing-user-gesture.html
@@ -2,10 +2,12 @@
 <script src="../../resources/testharness.js"></script>
 <script src="../../resources/testharnessreport.js"></script>
 <script src="../../resources/bluetooth/bluetooth-helpers.js"></script>
+<script src="../../resources/bluetooth/web-bluetooth-test.js"></script>
+<script src="../../resources/mojo-helpers.js"></script>
 <script>
 'use strict';
 promise_test(t => {
-  return setBluetoothFakeAdapter('HeartRateAdapter')
+  return setUpHealthThermometerAndHeartRateDevices()
     .then(() => promise_rejects(
       t, 'SecurityError', navigator.bluetooth.requestDevice({
         filters: [{services: ['heart_rate']}]})));
diff --git a/third_party/WebKit/LayoutTests/bluetooth/requestDevice/request-from-iframe.html b/third_party/WebKit/LayoutTests/bluetooth/requestDevice/request-from-iframe.html
index 1a27ed9..c942d00 100644
--- a/third_party/WebKit/LayoutTests/bluetooth/requestDevice/request-from-iframe.html
+++ b/third_party/WebKit/LayoutTests/bluetooth/requestDevice/request-from-iframe.html
@@ -2,6 +2,8 @@
 <script src="../../resources/testharness.js"></script>
 <script src="../../resources/testharnessreport.js"></script>
 <script src="../../resources/bluetooth/bluetooth-helpers.js"></script>
+<script src="../../resources/bluetooth/web-bluetooth-test.js"></script>
+<script src="../../resources/mojo-helpers.js"></script>
 <body>
   <script>
   "use strict";
@@ -36,7 +38,7 @@
       });
     });
 
-    return setBluetoothFakeAdapter('HeartRateAdapter')
+    return setUpHealthThermometerAndHeartRateDevices()
       .then(() => {
         for (let i = 0; i < numIframes; i++) {
           let iframe = document.createElement('iframe');
diff --git a/third_party/WebKit/LayoutTests/bluetooth/requestDevice/same-device.html b/third_party/WebKit/LayoutTests/bluetooth/requestDevice/same-device.html
index 9bd54a1..4b464539 100644
--- a/third_party/WebKit/LayoutTests/bluetooth/requestDevice/same-device.html
+++ b/third_party/WebKit/LayoutTests/bluetooth/requestDevice/same-device.html
@@ -2,13 +2,15 @@
 <script src="../../resources/testharness.js"></script>
 <script src="../../resources/testharnessreport.js"></script>
 <script src="../../resources/bluetooth/bluetooth-helpers.js"></script>
+<script src="../../resources/bluetooth/web-bluetooth-test.js"></script>
+<script src="../../resources/mojo-helpers.js"></script>
 <script>
 'use strict';
 promise_test(() => {
   let devices = [];
   let push = device => devices.push(device);
 
-  return setBluetoothFakeAdapter('HeartRateAdapter')
+  return setUpHealthThermometerAndHeartRateDevices()
     .then(() => requestDeviceWithKeyDown({
       filters: [{services: [heart_rate.alias]}]}))
     .then(push)
diff --git a/third_party/WebKit/LayoutTests/bluetooth/requestDevice/single-filter-single-service.html b/third_party/WebKit/LayoutTests/bluetooth/requestDevice/single-filter-single-service.html
index 77205fd..0647036 100644
--- a/third_party/WebKit/LayoutTests/bluetooth/requestDevice/single-filter-single-service.html
+++ b/third_party/WebKit/LayoutTests/bluetooth/requestDevice/single-filter-single-service.html
@@ -2,12 +2,14 @@
 <script src="../../resources/testharness.js"></script>
 <script src="../../resources/testharnessreport.js"></script>
 <script src="../../resources/bluetooth/bluetooth-helpers.js"></script>
+<script src="../../resources/bluetooth/web-bluetooth-test.js"></script>
+<script src="../../resources/mojo-helpers.js"></script>
 <script>
 'use strict';
 promise_test(() => {
-  return setBluetoothFakeAdapter('GlucoseHeartRateAdapter')
+  return setUpHealthThermometerAndHeartRateDevices()
     .then(() => requestDeviceWithKeyDown({
-      filters: [{services: ['glucose']}]}))
-    .then(device => assert_equals(device.name, 'Glucose Device'));
+      filters: [{services: ['health_thermometer']}]}))
+    .then(device => assert_equals(device.name, 'Health Thermometer'));
 }, 'Simple filter selects matching device.');
 </script>
diff --git a/third_party/WebKit/LayoutTests/compositing/overflow/absolute-element-in-isolated-composited-ancestor-expected.html b/third_party/WebKit/LayoutTests/compositing/overflow/absolute-element-in-isolated-composited-ancestor-expected.html
new file mode 100644
index 0000000..6710eba
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/compositing/overflow/absolute-element-in-isolated-composited-ancestor-expected.html
@@ -0,0 +1,45 @@
+<!DOCTYPE html>
+<style>
+body {
+  margin: 0px;
+}
+
+.scroller {
+  overflow: scroll;
+  width: 200px;
+  height: 600px;
+}
+
+.box {
+  background: rgba(0, 255, 0, 0.9);
+  position: relative;
+  width: 185px;
+  height: 50px;
+  top: 200px;
+}
+
+.indicator {
+  position: absolute;
+  width: 185px;
+  height: 50px;
+  background: red; /* covered up by .box when working */
+}
+
+.container {
+  width: 100%;
+  height: 1000px;
+  background: grey;
+}
+</style>
+
+<div id="scroller" class="scroller">
+  <div class="container">
+    <div class="indicator"></div>
+    <div class="box"></div>
+  </div>
+</div>
+
+<script>
+  let scroller = document.getElementById('scroller');
+  scroller.scrollTop = 200;
+</script>
diff --git a/third_party/WebKit/LayoutTests/compositing/overflow/absolute-element-in-isolated-composited-ancestor.html b/third_party/WebKit/LayoutTests/compositing/overflow/absolute-element-in-isolated-composited-ancestor.html
new file mode 100644
index 0000000..b698fb26
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/compositing/overflow/absolute-element-in-isolated-composited-ancestor.html
@@ -0,0 +1,66 @@
+<!DOCTYPE html>
+<style>
+body {
+  margin: 0px;
+}
+
+.scroller {
+  overflow: scroll;
+  width: 200px;
+  height: 600px;
+}
+
+.composited {
+  backface-visibility: hidden;
+  isolation: isolate;
+}
+
+.box {
+  background: rgba(0, 255, 0, 0.9);
+  position: absolute;
+  width: 185px;
+  height: 50px;
+  top: 0px;
+}
+
+.indicator {
+  position: absolute;
+  width: 185px;
+  height: 50px;
+  background: red; /* covered up by .box when working */
+}
+
+.container {
+  width: 100%;
+  height: 1000px;
+  background: grey;
+}
+</style>
+
+<div id="scroller" class="scroller">
+  <div class="composited container">
+    <div class="indicator"></div>
+    <div class="box"></div>
+  </div>
+</div>
+
+<script>
+  if (window.testRunner)
+    testRunner.waitUntilDone()
+
+  function doTest() {
+    let scroller = document.getElementById('scroller');
+    window.requestAnimationFrame(function() {
+      scroller.scrollTop = 200;
+      if (window.testRunner)
+        testRunner.notifyDone();
+    });
+  }
+
+  window.addEventListener('load', function() {
+    window.requestAnimationFrame(function() {
+      window.requestAnimationFrame(doTest);
+    })
+  });
+</script>
+
diff --git a/third_party/WebKit/LayoutTests/compositing/overflow/nested-render-surfaces-with-intervening-clip-expected.png b/third_party/WebKit/LayoutTests/compositing/overflow/nested-render-surfaces-with-intervening-clip-expected.png
index 26f10e94..ce412b62 100644
--- a/third_party/WebKit/LayoutTests/compositing/overflow/nested-render-surfaces-with-intervening-clip-expected.png
+++ b/third_party/WebKit/LayoutTests/compositing/overflow/nested-render-surfaces-with-intervening-clip-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/fast/css/resources/image-url-var.css b/third_party/WebKit/LayoutTests/fast/css/resources/image-url-var.css
new file mode 100644
index 0000000..af5c69d
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/css/resources/image-url-var.css
@@ -0,0 +1,31 @@
+.background.image-set.var {
+  --test: url('test.png');
+  background: -webkit-image-set(var(--test) 1x);
+}
+.background.image-set.inline {
+  background: -webkit-image-set(url('test.png') 1x);
+}
+
+.background.url.var {
+  --test: url('test.png');
+  background: var(--test);
+}
+.background.url.inline {
+  background: url('test.png');
+}
+
+.background-image.image-set.var {
+  --test: url('test.png');
+  background-image: -webkit-image-set(var(--test) 1x);
+}
+.background-image.image-set.inline {
+  background-image: -webkit-image-set(url('test.png') 1x);
+}
+
+.background-image.url.var {
+  --test: url('test.png');
+  background-image: var(--test);
+}
+.background-image.url.inline {
+  background-image: url('test.png');
+}
diff --git a/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-top-auto-get-computedstyle.html b/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-top-auto-get-computedstyle.html
new file mode 100644
index 0000000..3c2cf352
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-top-auto-get-computedstyle.html
@@ -0,0 +1,42 @@
+<!DOCTYPE html>
+<script src="../../../resources/testharness.js"></script>
+<script src="../../../resources/testharnessreport.js"></script>
+
+<style>
+#without_top {
+  top: auto;
+}
+
+#with_top {
+  top: 0px;
+}
+
+#with_bottom {
+  bottom: 0px;
+}
+
+.box {
+  position: sticky;
+}
+</style>
+
+<div class="box" id="without_top"></div>
+<div class="box" id="with_top"></div>
+<div class="box" id="with_bottom"></div>
+
+<script>
+test(() => {
+  var element = document.getElementById('without_top');
+  assert_equals(getComputedStyle(element).top, 'auto');
+}, 'top property should be auto if not specified.');
+
+test(() => {
+  var element = document.getElementById('with_top');
+  assert_equals(getComputedStyle(element).top, '0px');
+}, 'top property should be the actual value if specified.');
+
+test(() => {
+  var element = document.getElementById('with_bottom');
+  assert_equals(getComputedStyle(element).top, 'auto');
+}, 'top property should be auto if only bottom is specified.');
+</script>
diff --git a/third_party/WebKit/LayoutTests/fast/css/variables/computed-image-url.html b/third_party/WebKit/LayoutTests/fast/css/variables/computed-image-url.html
new file mode 100644
index 0000000..bd225765
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/css/variables/computed-image-url.html
@@ -0,0 +1,26 @@
+<!DOCTYPE html>
+<script src="../../../resources/testharness.js"></script>
+<script src="../../../resources/testharnessreport.js"></script>
+
+<div id="target"></div>
+
+<script>
+function testImageVar(property, value) {
+  test(() => {
+    target.style.setProperty('--test', value);
+    target.style[property] = 'var(--test)';
+    var actual = getComputedStyle(target)[property];
+
+    target.style[property] = value;
+    assert_not_equals(target.style[property], '', value + ' must be valid for ' + property);
+    var expected = getComputedStyle(target)[property];
+
+    assert_equals(actual, expected);
+  }, property + ' should resolve ' + value + ' the same whether via var() or not.');
+}
+
+testImageVar('background-image', 'url("image.png")');
+testImageVar('background-image', '-webkit-image-set(url("image.png") 1x)');
+testImageVar('background', 'url("image.png")');
+testImageVar('background', '-webkit-image-set(url("image.png") 1x)');
+</script>
diff --git a/third_party/WebKit/LayoutTests/fast/css/variables/computed-stylesheet-image-url.html b/third_party/WebKit/LayoutTests/fast/css/variables/computed-stylesheet-image-url.html
new file mode 100644
index 0000000..c0008d69
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/css/variables/computed-stylesheet-image-url.html
@@ -0,0 +1,35 @@
+<!DOCTYPE html>
+
+<script src="../../../resources/testharness.js"></script>
+<script src="../../../resources/testharnessreport.js"></script>
+
+<!-- The linked stylesheet must not be in the same directory as this test file. -->
+<!-- This is intended to test that relative URLs in stylesheets remain relative -->
+<!-- to the stylesheet's directory rather than the page that uses it. -->
+<link href="../resources/image-url-var.css" rel="stylesheet">
+
+<div id="target"></div>
+
+<script>
+for (var property of ['background', 'background-image']) {
+  for (var value of ['image-set', 'url']) {
+    test(() => {
+      target.classList.remove(...target.classList);
+      assert_equals(target.classList.length, 0);
+      var initial = getComputedStyle(target)[property];
+
+      target.classList.add(property);
+      target.classList.add(value);
+      target.classList.add('var');
+      var actual = getComputedStyle(target)[property];
+
+      target.classList.remove('var');
+      target.classList.add('inline');
+      var expected = getComputedStyle(target)[property];
+      assert_not_equals(expected, initial);
+
+      assert_equals(actual, expected);
+    }, property + ' should resolve ' + value + ' the same whether via var() or not.');
+  }
+}
+</script>
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector/console-test.js b/third_party/WebKit/LayoutTests/http/tests/inspector/console-test.js
index 2001694..d23a82e 100644
--- a/third_party/WebKit/LayoutTests/http/tests/inspector/console-test.js
+++ b/third_party/WebKit/LayoutTests/http/tests/inspector/console-test.js
@@ -394,19 +394,14 @@
 
 InspectorTest.changeExecutionContext = function(namePrefix)
 {
-    var selector = Console.ConsoleView.instance()._consoleContextSelector._selectElement;
-    var option = selector.firstChild;
-    while (option) {
-        if (option.textContent && option.textContent.trim().startsWith(namePrefix))
-            break;
-        option = option.nextSibling;
+    var selector = Console.ConsoleView.instance()._consoleContextSelector;
+    for (var executionContext of selector._list._items) {
+        if (selector._titleFor(executionContext).startsWith(namePrefix)) {
+            UI.context.setFlavor(SDK.ExecutionContext, executionContext);
+            return;
+        }
     }
-    if (!option) {
-        InspectorTest.addResult("FAILED: context with prefix: "  + namePrefix + " not found in the context list");
-        return;
-    }
-    option.selected = true;
-    Console.ConsoleView.instance()._consoleContextSelector._executionContextChanged();
+    InspectorTest.addResult("FAILED: context with prefix: "  + namePrefix + " not found in the context list");
 }
 
 InspectorTest.waitForConsoleMessages = function(expectedCount, callback)
diff --git a/third_party/WebKit/LayoutTests/inspector/console/console-context-selector.html b/third_party/WebKit/LayoutTests/inspector/console/console-context-selector.html
index 21c236a3..cd01163 100644
--- a/third_party/WebKit/LayoutTests/inspector/console/console-context-selector.html
+++ b/third_party/WebKit/LayoutTests/inspector/console/console-context-selector.html
@@ -96,13 +96,13 @@
 
   function dump() {
     var consoleView = Console.ConsoleView.instance();
-    var select = consoleView._executionContextComboBox.selectElement();
+    var selector = consoleView._consoleContextSelector;
     InspectorTest.addResult('Console context selector:');
-    for (var i = 0; i < select.options.length; i++) {
-      var option = select.options[i];
-      var selected = select.selectedIndex === i;
-      var text = option.text.replace(new RegExp('\u00a0', 'g'), '_');
-      InspectorTest.addResult(`${selected ? '*' : ' '} ${text} ${option.disabled ? '[disabled]' : ''}`);
+    for (var executionContext of selector._list._items) {
+      var selected = selector._list.selectedItem() === executionContext;
+      var text = '____'.repeat(selector._depthFor(executionContext)) + selector._titleFor(executionContext);
+      var disabled = !selector.isItemSelectable(executionContext);
+      InspectorTest.addResult(`${selected ? '*' : ' '} ${text} ${disabled ? '[disabled]' : ''}`);
     }
   }
 }
diff --git a/third_party/WebKit/LayoutTests/inspector/sources/debugger-pause/debugger-eval-on-call-frame-inside-iframe.html b/third_party/WebKit/LayoutTests/inspector/sources/debugger-pause/debugger-eval-on-call-frame-inside-iframe.html
index e6f5926..ba6754f 100644
--- a/third_party/WebKit/LayoutTests/inspector/sources/debugger-pause/debugger-eval-on-call-frame-inside-iframe.html
+++ b/third_party/WebKit/LayoutTests/inspector/sources/debugger-pause/debugger-eval-on-call-frame-inside-iframe.html
@@ -54,7 +54,7 @@
         {
             var expression = copy.shift();
             if (expression)
-                InspectorTest.evaluateInConsoleAndDump(expression, inner);
+                InspectorTest.evaluateInConsoleAndDump(expression, inner, true);
             else
                 callback();
         }
diff --git a/third_party/WebKit/LayoutTests/paint/printing/print-box-shadow-expected.png b/third_party/WebKit/LayoutTests/paint/printing/print-box-shadow-expected.png
new file mode 100644
index 0000000..5325356
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/paint/printing/print-box-shadow-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/paint/printing/print-box-shadow-expected.txt b/third_party/WebKit/LayoutTests/paint/printing/print-box-shadow-expected.txt
new file mode 100644
index 0000000..5c3e113
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/paint/printing/print-box-shadow-expected.txt
@@ -0,0 +1,9 @@
+layer at (0,0) size 1066x799
+  LayoutView at (0,0) size 1066x799
+layer at (0,0) size 1066x143
+  LayoutBlockFlow {HTML} at (0,0) size 1066x143
+    LayoutBlockFlow {BODY} at (8,8) size 1050x127
+layer at (8,8) size 332x127 clip at (9,9) size 330x125
+  LayoutBlockFlow {DIV} at (0,0) size 332x127 [border: (1px solid #000000)]
+layer at (9,9) size 330x125
+  LayoutBlockFlow {DIV} at (1,1) size 330x125
diff --git a/third_party/WebKit/LayoutTests/paint/printing/print-box-shadow.html b/third_party/WebKit/LayoutTests/paint/printing/print-box-shadow.html
new file mode 100644
index 0000000..69b57f8e
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/paint/printing/print-box-shadow.html
@@ -0,0 +1,24 @@
+<!doctype HTML>
+<style>
+#parent {
+    height: 125px;
+    width: 330px;
+    overflow: hidden;
+    border: 1px solid black;
+}
+
+#child {
+    box-shadow: rgba(0, 0, 0, 0.2) 0px 8px 17px 0px;
+    height: 125px;
+    overflow:hidden;
+}
+
+</style>
+<div id="parent"> 
+    <div id="child">
+    </div>
+</div>
+<script>
+  if (window.testRunner)
+    testRunner.setPrinting();
+</script>
diff --git a/third_party/WebKit/LayoutTests/resources/bluetooth/bluetooth-helpers.js b/third_party/WebKit/LayoutTests/resources/bluetooth/bluetooth-helpers.js
index d4ace28..97919a86 100644
--- a/third_party/WebKit/LayoutTests/resources/bluetooth/bluetooth-helpers.js
+++ b/third_party/WebKit/LayoutTests/resources/bluetooth/bluetooth-helpers.js
@@ -422,3 +422,28 @@
     optionalServices: ['heart_rate']
   }];
 }
+
+function setUpPreconnectedDevice({
+  address = '00:00:00:00:00:00', name = 'LE Device', knownServiceUUIDs = []}) {
+  return navigator.bluetooth.test.simulateCentral({state: 'powered-on'})
+    .then(fake_central => fake_central.simulatePreconnectedPeripheral({
+      address: address,
+      name: name,
+      knownServiceUUIDs: knownServiceUUIDs,
+    }));
+}
+
+function setUpHealthThermometerAndHeartRateDevices() {
+  return navigator.bluetooth.test.simulateCentral({state: 'powered-on'})
+   .then(fake_central => Promise.all([
+     fake_central.simulatePreconnectedPeripheral({
+       address: '09:09:09:09:09:09',
+       name: 'Health Thermometer',
+       knownServiceUUIDs: ['generic_access', 'health_thermometer'],
+     }),
+     fake_central.simulatePreconnectedPeripheral({
+       address: '08:08:08:08:08:08',
+       name: 'Heart Rate',
+       knownServiceUUIDs: ['generic_access', 'heart_rate'],
+     })]));
+}
diff --git a/third_party/WebKit/LayoutTests/resources/bluetooth/web-bluetooth-test.js b/third_party/WebKit/LayoutTests/resources/bluetooth/web-bluetooth-test.js
index 59e5d5a..450c27d 100644
--- a/third_party/WebKit/LayoutTests/resources/bluetooth/web-bluetooth-test.js
+++ b/third_party/WebKit/LayoutTests/resources/bluetooth/web-bluetooth-test.js
@@ -26,6 +26,19 @@
     return mojo_;
   }
 
+  function toMojoCentralState(state) {
+    switch (state) {
+      case 'absent':
+        return mojo_.CentralState.ABSENT;
+      case 'powered-off':
+        return mojo_.CentralState.POWERED_OFF;
+      case 'powered-on':
+        return mojo_.CentralState.POWERED_ON;
+      default:
+        throw `Unsupported value ${state} for state.`;
+    }
+  }
+
   class FakeBluetooth {
     constructor() {
       this.fake_bluetooth_ptr_ = undefined;
@@ -45,9 +58,10 @@
       // TODO(crbug.com/569709): Remove once setBluetoothFakeAdapter is no
       // longer used.
       await setBluetoothFakeAdapter('');
+      await this.initFakeBluetoothInterfacePtr_();
 
       if (typeof supported !== 'boolean') throw 'Type Not Supported';
-      await (await this.getFakeBluetoothInterface_()).setLESupported(supported);
+      await this.fake_bluetooth_ptr_.setLESupported(supported);
     }
 
     // Returns a promise that resolves with a FakeCentral that clients can use
@@ -71,33 +85,17 @@
       // TODO(crbug.com/569709): Remove once setBluetoothFakeAdapter is no
       // longer used.
       await setBluetoothFakeAdapter('');
+      await this.initFakeBluetoothInterfacePtr_();
 
       await this.setLESupported(true);
-      let mojo = await loadFakeBluetoothInterfaces();
-
-      let mojo_manager_state;
-      switch (state) {
-        case 'absent':
-          mojo_manager_state = mojo.CentralState.ABSENT;
-          break;
-        case 'powered-off':
-          mojo_manager_state = mojo.CentralState.POWERED_OFF;
-          break;
-        case 'powered-on':
-          mojo_manager_state = mojo.CentralState.POWERED_ON;
-          break;
-        default:
-          throw `Unsupported value ${state} for state.`;
-      }
 
       let {fake_central:fake_central_ptr} =
-        await (await this.getFakeBluetoothInterface_()).simulateCentral(
-          mojo_manager_state);
-
+        await this.fake_bluetooth_ptr_.simulateCentral(
+          toMojoCentralState(state));
       return new FakeCentral(fake_central_ptr);
     }
 
-    async getFakeBluetoothInterface_() {
+    async initFakeBluetoothInterfacePtr_() {
       if (typeof this.fake_bluetooth_ptr_ !== 'undefined') {
         return this.fake_bluetooth_ptr_;
       }
@@ -106,8 +104,6 @@
 
       this.fake_bluetooth_ptr_ = new mojo.FakeBluetoothPtr(
         mojo.interfaces.getInterface(mojo.FakeBluetooth.name));
-
-      return this.fake_bluetooth_ptr_;
     }
   }
 
@@ -116,7 +112,45 @@
   // performed by the device in the Central/Observer role.
   class FakeCentral {
     constructor(fake_central_ptr) {
-      this.fake_central_ptr = fake_central_ptr;
+      this.fake_central_ptr_ = fake_central_ptr;
+      this.peripherals_ = new Map();
+    }
+
+    // Simulates a peripheral with |address|, |name| and |known_service_uuids|
+    // that has already been connected to the system. If the peripheral existed
+    // already it updates its name and known UUIDs. |known_service_uuids| should
+    // be an array of BluetoothServiceUUIDs
+    // https://webbluetoothcg.github.io/web-bluetooth/#typedefdef-bluetoothserviceuuid
+    //
+    // Platforms offer methods to retrieve devices that have already been
+    // connected to the system or weren't connected through the UA e.g. a user
+    // connected a peripheral through the system's settings. This method is
+    // intended to simulate peripherals that those methods would return.
+    async simulatePreconnectedPeripheral({
+      address, name, knownServiceUUIDs = []}) {
+
+      // Canonicalize and convert to mojo UUIDs.
+      knownServiceUUIDs.forEach((val, i, arr) => {
+        knownServiceUUIDs[i] = {uuid: BluetoothUUID.getService(val)};
+      });
+
+      await this.fake_central_ptr_.simulatePreconnectedPeripheral(
+        address, name, knownServiceUUIDs);
+
+      let peripheral = this.peripherals_.get(address);
+      if (peripheral === undefined) {
+        peripheral = new FakePeripheral(address, this);
+        this.peripherals_.set(address, peripheral);
+      }
+
+      return peripheral;
+    }
+  }
+
+  class FakePeripheral {
+    constructor(address, fake_central) {
+      this.address = address;
+      this.fake_central_ = fake_central;
     }
   }
 
diff --git a/third_party/WebKit/Source/bindings/core/v8/BUILD.gn b/third_party/WebKit/Source/bindings/core/v8/BUILD.gn
index 2e25ee0..b5c4e82 100644
--- a/third_party/WebKit/Source/bindings/core/v8/BUILD.gn
+++ b/third_party/WebKit/Source/bindings/core/v8/BUILD.gn
@@ -15,6 +15,8 @@
   "$blink_core_output_dir/animation/AnimationEffectTimingProperties.h",
   "$blink_core_output_dir/animation/ComputedTimingProperties.cpp",
   "$blink_core_output_dir/animation/ComputedTimingProperties.h",
+  "$blink_core_output_dir/animation/KeyframeAnimationOptions.cpp",
+  "$blink_core_output_dir/animation/KeyframeAnimationOptions.h",
   "$blink_core_output_dir/animation/KeyframeEffectOptions.cpp",
   "$blink_core_output_dir/animation/KeyframeEffectOptions.h",
   "$blink_core_output_dir/css/FontFaceDescriptors.cpp",
@@ -230,6 +232,8 @@
   "$bindings_core_v8_output_dir/StringOrUnrestrictedDoubleSequence.h",
   "$bindings_core_v8_output_dir/USVStringSequenceSequenceOrUSVStringOrURLSearchParams.cpp",
   "$bindings_core_v8_output_dir/USVStringSequenceSequenceOrUSVStringOrURLSearchParams.h",
+  "$bindings_core_v8_output_dir/UnrestrictedDoubleOrKeyframeAnimationOptions.cpp",
+  "$bindings_core_v8_output_dir/UnrestrictedDoubleOrKeyframeAnimationOptions.h",
   "$bindings_core_v8_output_dir/UnrestrictedDoubleOrKeyframeEffectOptions.cpp",
   "$bindings_core_v8_output_dir/UnrestrictedDoubleOrKeyframeEffectOptions.h",
   "$bindings_core_v8_output_dir/UnrestrictedDoubleOrString.cpp",
diff --git a/third_party/WebKit/Source/core/animation/ElementAnimation.h b/third_party/WebKit/Source/core/animation/ElementAnimation.h
index 085f7ef5..926542cc 100644
--- a/third_party/WebKit/Source/core/animation/ElementAnimation.h
+++ b/third_party/WebKit/Source/core/animation/ElementAnimation.h
@@ -32,7 +32,7 @@
 #define ElementAnimation_h
 
 #include "bindings/core/v8/DictionarySequenceOrDictionary.h"
-#include "bindings/core/v8/UnrestrictedDoubleOrKeyframeEffectOptions.h"
+#include "bindings/core/v8/UnrestrictedDoubleOrKeyframeAnimationOptions.h"
 #include "core/animation/DocumentTimeline.h"
 #include "core/animation/EffectInput.h"
 #include "core/animation/ElementAnimations.h"
@@ -52,11 +52,12 @@
   STATIC_ONLY(ElementAnimation);
 
  public:
-  static Animation* animate(ScriptState* script_state,
-                            Element& element,
-                            const DictionarySequenceOrDictionary& effect_input,
-                            UnrestrictedDoubleOrKeyframeEffectOptions options,
-                            ExceptionState& exception_state) {
+  static Animation* animate(
+      ScriptState* script_state,
+      Element& element,
+      const DictionarySequenceOrDictionary& effect_input,
+      UnrestrictedDoubleOrKeyframeAnimationOptions options,
+      ExceptionState& exception_state) {
     EffectModel* effect = EffectInput::Convert(
         &element, effect_input, ExecutionContext::From(script_state),
         exception_state);
@@ -68,9 +69,9 @@
                               exception_state))
       return nullptr;
 
-    if (options.isKeyframeEffectOptions()) {
+    if (options.isKeyframeAnimationOptions()) {
       Animation* animation = animate(element, effect, timing);
-      animation->setId(options.getAsKeyframeEffectOptions().id());
+      animation->setId(options.getAsKeyframeAnimationOptions().id());
       return animation;
     }
     return animate(element, effect, timing);
diff --git a/third_party/WebKit/Source/core/animation/ElementAnimation.idl b/third_party/WebKit/Source/core/animation/ElementAnimation.idl
index 025edd4..73e3ca2 100644
--- a/third_party/WebKit/Source/core/animation/ElementAnimation.idl
+++ b/third_party/WebKit/Source/core/animation/ElementAnimation.idl
@@ -36,6 +36,6 @@
 
 partial interface Element {
     // TODO(dstockwell): The argument types do not match the spec.
-    [CallWith=ScriptState, Measure, RaisesException] Animation animate((sequence<Dictionary> or Dictionary)? effect, optional (unrestricted double or KeyframeEffectOptions) options);
+    [CallWith=ScriptState, Measure, RaisesException] Animation animate((sequence<Dictionary> or Dictionary)? effect, optional (unrestricted double or KeyframeAnimationOptions) options);
     [RuntimeEnabled=WebAnimationsAPI] sequence<Animation> getAnimations();
 };
diff --git a/third_party/WebKit/Source/core/animation/KeyframeAnimationOptions.idl b/third_party/WebKit/Source/core/animation/KeyframeAnimationOptions.idl
new file mode 100644
index 0000000..d83463e
--- /dev/null
+++ b/third_party/WebKit/Source/core/animation/KeyframeAnimationOptions.idl
@@ -0,0 +1,9 @@
+// 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.
+
+// https://w3c.github.io/web-animations/#dictdef-keyframeanimationoptions
+
+dictionary KeyframeAnimationOptions : KeyframeEffectOptions {
+    DOMString id = "";
+};
diff --git a/third_party/WebKit/Source/core/animation/KeyframeEffectOptions.idl b/third_party/WebKit/Source/core/animation/KeyframeEffectOptions.idl
index ed76804..ac46caf7 100644
--- a/third_party/WebKit/Source/core/animation/KeyframeEffectOptions.idl
+++ b/third_party/WebKit/Source/core/animation/KeyframeEffectOptions.idl
@@ -6,5 +6,4 @@
 
 dictionary KeyframeEffectOptions : AnimationEffectTimingProperties {
     // TODO(alancutter): Implement iterationComposite, composite and spacing.
-    DOMString id = "";
 };
diff --git a/third_party/WebKit/Source/core/animation/TimingInput.cpp b/third_party/WebKit/Source/core/animation/TimingInput.cpp
index 51b438a..e6e6414 100644
--- a/third_party/WebKit/Source/core/animation/TimingInput.cpp
+++ b/third_party/WebKit/Source/core/animation/TimingInput.cpp
@@ -5,6 +5,7 @@
 #include "core/animation/TimingInput.h"
 
 #include "bindings/core/v8/ExceptionState.h"
+#include "bindings/core/v8/UnrestrictedDoubleOrKeyframeAnimationOptions.h"
 #include "bindings/core/v8/UnrestrictedDoubleOrKeyframeEffectOptions.h"
 #include "core/animation/AnimationInputHelpers.h"
 #include "core/animation/KeyframeEffectOptions.h"
@@ -138,6 +139,24 @@
   return false;
 }
 
+bool TimingInput::Convert(
+    const UnrestrictedDoubleOrKeyframeAnimationOptions& options,
+    Timing& timing_output,
+    Document* document,
+    ExceptionState& exception_state) {
+  if (options.isKeyframeAnimationOptions()) {
+    return Convert(options.getAsKeyframeAnimationOptions(), timing_output,
+                   document, exception_state);
+  } else if (options.isUnrestrictedDouble()) {
+    return Convert(options.getAsUnrestrictedDouble(), timing_output,
+                   exception_state);
+  } else if (options.isNull()) {
+    return true;
+  }
+  NOTREACHED();
+  return false;
+}
+
 bool TimingInput::Convert(const KeyframeEffectOptions& timing_input,
                           Timing& timing_output,
                           Document* document,
@@ -170,6 +189,15 @@
   return true;
 }
 
+bool TimingInput::Convert(const KeyframeAnimationOptions& timing_input,
+                          Timing& timing_output,
+                          Document* document,
+                          ExceptionState& exception_state) {
+  // The "id" field isn't used, so upcast to KeyframeEffectOptions.
+  const KeyframeEffectOptions* const timing_input_ptr = &timing_input;
+  return Convert(*timing_input_ptr, timing_output, document, exception_state);
+}
+
 bool TimingInput::Convert(double duration,
                           Timing& timing_output,
                           ExceptionState& exception_state) {
diff --git a/third_party/WebKit/Source/core/animation/TimingInput.h b/third_party/WebKit/Source/core/animation/TimingInput.h
index 9f15497..5ab4b58 100644
--- a/third_party/WebKit/Source/core/animation/TimingInput.h
+++ b/third_party/WebKit/Source/core/animation/TimingInput.h
@@ -13,8 +13,10 @@
 
 class Document;
 class ExceptionState;
+class KeyframeAnimationOptions;
 class KeyframeEffectOptions;
 class UnrestrictedDoubleOrString;
+class UnrestrictedDoubleOrKeyframeAnimationOptions;
 class UnrestrictedDoubleOrKeyframeEffectOptions;
 
 class CORE_EXPORT TimingInput {
@@ -25,10 +27,19 @@
                       Timing& timing_output,
                       Document*,
                       ExceptionState&);
+  static bool Convert(const UnrestrictedDoubleOrKeyframeAnimationOptions&,
+                      Timing& timing_output,
+                      Document*,
+                      ExceptionState&);
   static bool Convert(const KeyframeEffectOptions& timing_input,
                       Timing& timing_output,
                       Document*,
                       ExceptionState&);
+  static bool Convert(const KeyframeAnimationOptions& timing_input,
+                      Timing& timing_output,
+                      Document*,
+                      ExceptionState&);
+
   static bool Convert(double duration, Timing& timing_output, ExceptionState&);
 
   static void SetStartDelay(Timing&, double start_delay);
diff --git a/third_party/WebKit/Source/core/animation/TimingInputTest.cpp b/third_party/WebKit/Source/core/animation/TimingInputTest.cpp
index 5e9f6d8..11faae80 100644
--- a/third_party/WebKit/Source/core/animation/TimingInputTest.cpp
+++ b/third_party/WebKit/Source/core/animation/TimingInputTest.cpp
@@ -5,6 +5,7 @@
 #include "core/animation/TimingInput.h"
 
 #include "bindings/core/v8/V8BindingForTesting.h"
+#include "bindings/core/v8/V8KeyframeAnimationOptions.h"
 #include "bindings/core/v8/V8KeyframeEffectOptions.h"
 #include "core/animation/AnimationEffectTiming.h"
 #include "core/animation/AnimationTestHelper.h"
@@ -17,38 +18,61 @@
 Timing ApplyTimingInputNumber(v8::Isolate* isolate,
                               String timing_property,
                               double timing_property_value,
-                              bool& timing_conversion_success) {
+                              bool& timing_conversion_success,
+                              bool is_keyframeeffectoptions = true) {
   v8::Local<v8::Object> timing_input = v8::Object::New(isolate);
   SetV8ObjectPropertyAsNumber(isolate, timing_input, timing_property,
                               timing_property_value);
-  KeyframeEffectOptions timing_input_dictionary;
   DummyExceptionStateForTesting exception_state;
-  V8KeyframeEffectOptions::toImpl(isolate, timing_input,
-                                  timing_input_dictionary, exception_state);
   Timing result;
-  timing_conversion_success =
-      TimingInput::Convert(timing_input_dictionary, result, nullptr,
-                           exception_state) &&
-      !exception_state.HadException();
+  if (is_keyframeeffectoptions) {
+    KeyframeEffectOptions timing_input_dictionary;
+    V8KeyframeEffectOptions::toImpl(isolate, timing_input,
+                                    timing_input_dictionary, exception_state);
+    timing_conversion_success =
+        TimingInput::Convert(timing_input_dictionary, result, nullptr,
+                             exception_state) &&
+        !exception_state.HadException();
+  } else {
+    KeyframeAnimationOptions timing_input_dictionary;
+    V8KeyframeAnimationOptions::toImpl(
+        isolate, timing_input, timing_input_dictionary, exception_state);
+    timing_conversion_success =
+        TimingInput::Convert(timing_input_dictionary, result, nullptr,
+                             exception_state) &&
+        !exception_state.HadException();
+  }
   return result;
 }
 
 Timing ApplyTimingInputString(v8::Isolate* isolate,
                               String timing_property,
                               String timing_property_value,
-                              bool& timing_conversion_success) {
+                              bool& timing_conversion_success,
+                              bool is_keyframeeffectoptions = true) {
   v8::Local<v8::Object> timing_input = v8::Object::New(isolate);
   SetV8ObjectPropertyAsString(isolate, timing_input, timing_property,
                               timing_property_value);
-  KeyframeEffectOptions timing_input_dictionary;
+
   DummyExceptionStateForTesting exception_state;
-  V8KeyframeEffectOptions::toImpl(isolate, timing_input,
-                                  timing_input_dictionary, exception_state);
   Timing result;
-  timing_conversion_success =
-      TimingInput::Convert(timing_input_dictionary, result, nullptr,
-                           exception_state) &&
-      !exception_state.HadException();
+  if (is_keyframeeffectoptions) {
+    KeyframeEffectOptions timing_input_dictionary;
+    V8KeyframeEffectOptions::toImpl(isolate, timing_input,
+                                    timing_input_dictionary, exception_state);
+    timing_conversion_success =
+        TimingInput::Convert(timing_input_dictionary, result, nullptr,
+                             exception_state) &&
+        !exception_state.HadException();
+  } else {
+    KeyframeAnimationOptions timing_input_dictionary;
+    V8KeyframeAnimationOptions::toImpl(
+        isolate, timing_input, timing_input_dictionary, exception_state);
+    timing_conversion_success =
+        TimingInput::Convert(timing_input_dictionary, result, nullptr,
+                             exception_state) &&
+        !exception_state.HadException();
+  }
   return result;
 }
 
@@ -81,6 +105,35 @@
                    .start_delay);
 }
 
+TEST(AnimationTimingInputTest, TimingInputStartDelayKeyframeAnimationOptions) {
+  V8TestingScope scope;
+  bool ignored_success;
+  EXPECT_EQ(1.1, ApplyTimingInputNumber(scope.GetIsolate(), "delay", 1100,
+                                        ignored_success, false)
+                     .start_delay);
+  EXPECT_EQ(-1, ApplyTimingInputNumber(scope.GetIsolate(), "delay", -1000,
+                                       ignored_success, false)
+                    .start_delay);
+  EXPECT_EQ(1, ApplyTimingInputString(scope.GetIsolate(), "delay", "1000",
+                                      ignored_success, false)
+                   .start_delay);
+  EXPECT_EQ(0, ApplyTimingInputString(scope.GetIsolate(), "delay", "1s",
+                                      ignored_success, false)
+                   .start_delay);
+  EXPECT_EQ(0, ApplyTimingInputString(scope.GetIsolate(), "delay", "Infinity",
+                                      ignored_success, false)
+                   .start_delay);
+  EXPECT_EQ(0, ApplyTimingInputString(scope.GetIsolate(), "delay", "-Infinity",
+                                      ignored_success, false)
+                   .start_delay);
+  EXPECT_EQ(0, ApplyTimingInputString(scope.GetIsolate(), "delay", "NaN",
+                                      ignored_success, false)
+                   .start_delay);
+  EXPECT_EQ(0, ApplyTimingInputString(scope.GetIsolate(), "delay", "rubbish",
+                                      ignored_success, false)
+                   .start_delay);
+}
+
 TEST(AnimationTimingInputTest, TimingInputEndDelay) {
   V8TestingScope scope;
   bool ignored_success;
@@ -375,4 +428,23 @@
   EXPECT_EQ(*control_timing.timing_function, *updated_timing.timing_function);
 }
 
+TEST(AnimationTimingInputTest, TimingInputEmptyKeyframeAnimationOptions) {
+  DummyExceptionStateForTesting exception_state;
+  Timing control_timing;
+  Timing updated_timing;
+  bool success = TimingInput::Convert(KeyframeAnimationOptions(),
+                                      updated_timing, nullptr, exception_state);
+  EXPECT_TRUE(success);
+  EXPECT_FALSE(exception_state.HadException());
+
+  EXPECT_EQ(control_timing.start_delay, updated_timing.start_delay);
+  EXPECT_EQ(control_timing.fill_mode, updated_timing.fill_mode);
+  EXPECT_EQ(control_timing.iteration_start, updated_timing.iteration_start);
+  EXPECT_EQ(control_timing.iteration_count, updated_timing.iteration_count);
+  EXPECT_TRUE(std::isnan(updated_timing.iteration_duration));
+  EXPECT_EQ(control_timing.playback_rate, updated_timing.playback_rate);
+  EXPECT_EQ(control_timing.direction, updated_timing.direction);
+  EXPECT_EQ(*control_timing.timing_function, *updated_timing.timing_function);
+}
+
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/core_idl_files.gni b/third_party/WebKit/Source/core/core_idl_files.gni
index ed326bd..3f45dd6 100644
--- a/third_party/WebKit/Source/core/core_idl_files.gni
+++ b/third_party/WebKit/Source/core/core_idl_files.gni
@@ -512,6 +512,7 @@
     get_path_info([
                     "animation/AnimationEffectTimingProperties.idl",
                     "animation/ComputedTimingProperties.idl",
+                    "animation/KeyframeAnimationOptions.idl",
                     "animation/KeyframeEffectOptions.idl",
                     "css/FontFaceDescriptors.idl",
                     "css/FontFaceSetLoadEventInit.idl",
diff --git a/third_party/WebKit/Source/core/css/CSSProperties.json5 b/third_party/WebKit/Source/core/css/CSSProperties.json5
index 6c129182..f1af434 100644
--- a/third_party/WebKit/Source/core/css/CSSProperties.json5
+++ b/third_party/WebKit/Source/core/css/CSSProperties.json5
@@ -1222,6 +1222,10 @@
       keywords: ["auto", "fit-content", "min-content", "max-content"],
       supports_percentage: true,
       typedom_types: ["Length"],
+      field_template: "storage_only",
+      field_type_path: "platform/Length",
+      field_group: "box",
+      default_value: "Length()",
     },
     {
       name: "hyphens",
@@ -1429,12 +1433,20 @@
       converter: "ConvertLengthMaxSizing",
       is_descriptor: true,
       interpolable: true,
+      field_template: "storage_only",
+      field_type_path: "platform/Length",
+      field_group: "box",
+      default_value: "Length(kMaxSizeNone)",
     },
     {
       name: "max-width",
       converter: "ConvertLengthMaxSizing",
       is_descriptor: true,
       interpolable: true,
+      field_template: "storage_only",
+      field_type_path: "platform/Length",
+      field_group: "box",
+      default_value: "Length(kMaxSizeNone)",
     },
     {
       name: "min-height",
@@ -1442,6 +1454,10 @@
       converter: "ConvertLengthSizing",
       is_descriptor: true,
       interpolable: true,
+      field_template: "storage_only",
+      field_type_path: "platform/Length",
+      field_group: "box",
+      default_value: "Length()",
     },
     {
       name: "min-width",
@@ -1449,6 +1465,10 @@
       converter: "ConvertLengthSizing",
       is_descriptor: true,
       interpolable: true,
+      field_template: "storage_only",
+      field_type_path: "platform/Length",
+      field_group: "box",
+      default_value: "Length()",
     },
     {
       name: "mix-blend-mode",
@@ -2496,6 +2516,10 @@
       keywords: ["auto", "fit-content", "min-content", "max-content"],
       supports_percentage: true,
       typedom_types: ["Length"],
+      field_template: "storage_only",
+      field_type_path: "platform/Length",
+      field_group: "box",
+      default_value: "Length()"
     },
     {
       name: "will-change",
@@ -2529,6 +2553,9 @@
       custom_all: true,
       interpolable: true,
       type_name: "int",
+      field_template: "storage_only",
+      field_group: "box",
+      default_value: "0"
     },
 
     // CSS logical props
diff --git a/third_party/WebKit/Source/core/css/CSSSyntaxDescriptor.cpp b/third_party/WebKit/Source/core/css/CSSSyntaxDescriptor.cpp
index d96dfaf..46ee79f 100644
--- a/third_party/WebKit/Source/core/css/CSSSyntaxDescriptor.cpp
+++ b/third_party/WebKit/Source/core/css/CSSSyntaxDescriptor.cpp
@@ -203,7 +203,7 @@
                                            bool is_animation_tainted) const {
   if (IsTokenStream()) {
     return CSSVariableParser::ParseRegisteredPropertyValue(
-        range, false, is_animation_tainted);
+        range, *context, false, is_animation_tainted);
   }
   range.ConsumeWhitespace();
   for (const CSSSyntaxComponent& component : syntax_components_) {
@@ -211,7 +211,7 @@
             ConsumeSyntaxComponent(component, range, context))
       return result;
   }
-  return CSSVariableParser::ParseRegisteredPropertyValue(range, true,
+  return CSSVariableParser::ParseRegisteredPropertyValue(range, *context, true,
                                                          is_animation_tainted);
 }
 
diff --git a/third_party/WebKit/Source/core/css/CSSVariableReferenceValue.cpp b/third_party/WebKit/Source/core/css/CSSVariableReferenceValue.cpp
index 01b8155..0fd8120 100644
--- a/third_party/WebKit/Source/core/css/CSSVariableReferenceValue.cpp
+++ b/third_party/WebKit/Source/core/css/CSSVariableReferenceValue.cpp
@@ -8,6 +8,7 @@
 
 DEFINE_TRACE_AFTER_DISPATCH(CSSVariableReferenceValue) {
   CSSValue::TraceAfterDispatch(visitor);
+  visitor->Trace(parser_context_);
 }
 
 String CSSVariableReferenceValue::CustomCSSText() const {
diff --git a/third_party/WebKit/Source/core/css/CSSVariableReferenceValue.h b/third_party/WebKit/Source/core/css/CSSVariableReferenceValue.h
index f8a21ae..2e3ec4f 100644
--- a/third_party/WebKit/Source/core/css/CSSVariableReferenceValue.h
+++ b/third_party/WebKit/Source/core/css/CSSVariableReferenceValue.h
@@ -7,17 +7,22 @@
 
 #include "core/css/CSSValue.h"
 #include "core/css/CSSVariableData.h"
+#include "core/css/parser/CSSParserContext.h"
 #include "platform/wtf/RefPtr.h"
 
 namespace blink {
 
 class CSSVariableReferenceValue : public CSSValue {
  public:
-  static CSSVariableReferenceValue* Create(PassRefPtr<CSSVariableData> data) {
-    return new CSSVariableReferenceValue(std::move(data));
+  static CSSVariableReferenceValue* Create(PassRefPtr<CSSVariableData> data,
+                                           const CSSParserContext& context) {
+    return new CSSVariableReferenceValue(std::move(data), context);
   }
 
   CSSVariableData* VariableDataValue() const { return data_.Get(); }
+  const CSSParserContext* ParserContext() const {
+    return parser_context_.Get();
+  }
 
   bool Equals(const CSSVariableReferenceValue& other) const {
     return data_ == other.data_;
@@ -27,10 +32,16 @@
   DECLARE_TRACE_AFTER_DISPATCH();
 
  private:
-  CSSVariableReferenceValue(PassRefPtr<CSSVariableData> data)
-      : CSSValue(kVariableReferenceClass), data_(std::move(data)) {}
+  CSSVariableReferenceValue(PassRefPtr<CSSVariableData> data,
+                            const CSSParserContext& context)
+      : CSSValue(kVariableReferenceClass),
+        data_(std::move(data)),
+        parser_context_(context) {
+    DCHECK(parser_context_);
+  }
 
   RefPtr<CSSVariableData> data_;
+  Member<const CSSParserContext> parser_context_;
 };
 
 DEFINE_CSS_VALUE_TYPE_CASTS(CSSVariableReferenceValue,
diff --git a/third_party/WebKit/Source/core/css/ComputedStyleCSSValueMapping.cpp b/third_party/WebKit/Source/core/css/ComputedStyleCSSValueMapping.cpp
index 1daf561..81c508b 100644
--- a/third_party/WebKit/Source/core/css/ComputedStyleCSSValueMapping.cpp
+++ b/third_party/WebKit/Source/core/css/ComputedStyleCSSValueMapping.cpp
@@ -224,7 +224,10 @@
   if (offset.IsAuto() && layout_object) {
     // If the property applies to a positioned element and the resolved value of
     // the display property is not none, the resolved value is the used value.
-    if (layout_object->IsInFlowPositioned()) {
+    // Position offsets have special meaning for position sticky so we return
+    // auto when offset.isAuto() on a sticky position object:
+    // https://crbug.com/703816.
+    if (layout_object->IsRelPositioned()) {
       // If e.g. left is auto and right is not auto, then left's computed value
       // is negative right. So we get the opposite length unit and see if it is
       // auto.
diff --git a/third_party/WebKit/Source/core/css/ComputedStyleExtraFields.json5 b/third_party/WebKit/Source/core/css/ComputedStyleExtraFields.json5
index e40c8d0..49c5b72 100644
--- a/third_party/WebKit/Source/core/css/ComputedStyleExtraFields.json5
+++ b/third_party/WebKit/Source/core/css/ComputedStyleExtraFields.json5
@@ -183,6 +183,13 @@
       type_name: "EVerticalAlign",
     },
     {
+      name: "VerticalAlignLength",
+      field_template: "storage_only",
+      default_value: "Length()",
+      field_type_path: "platform/Length",
+      field_group: "box",
+    },
+    {
       name: "border",
       field_template: "storage_only",
       field_type_path: "core/style/BorderData",
@@ -219,5 +226,29 @@
       default_value: "true",
       field_group: "visual",
     },
+    {
+      name: "HasAutoZIndex",
+      field_template: "storage_only",
+      type_name: "bool",
+      field_size: 1,
+      field_group: "box",
+      default_value: "true",
+    },
+    {
+      name: "BoxDecorationBreak",
+      field_template: "storage_only",
+      type_name: "EBoxDecorationBreak",
+      field_size: 1,
+      field_group: "box",
+      default_value: "EBoxDecorationBreak::kSlice",
+    },
+    {
+      name: "BoxSizing",
+      field_template: "storage_only",
+      type_name: "EBoxSizing",
+      field_size: 1,
+      field_group: "box",
+      default_value: "EBoxSizing::kContentBox",
+    },
   ],
 }
diff --git a/third_party/WebKit/Source/core/css/cssom/CSSUnparsedValue.cpp b/third_party/WebKit/Source/core/css/cssom/CSSUnparsedValue.cpp
index 7c48f2a..4c29033 100644
--- a/third_party/WebKit/Source/core/css/cssom/CSSUnparsedValue.cpp
+++ b/third_party/WebKit/Source/core/css/cssom/CSSUnparsedValue.cpp
@@ -87,9 +87,13 @@
   }
 
   CSSTokenizer tokenizer(tokens.ToString());
-  return CSSVariableReferenceValue::Create(CSSVariableData::Create(
-      tokenizer.TokenRange(), false /* isAnimationTainted */,
-      true /* needsVariableResolution */));
+  // TODO(alancutter): This should be using a real parser context instead of
+  // StrictCSSParserContext.
+  return CSSVariableReferenceValue::Create(
+      CSSVariableData::Create(tokenizer.TokenRange(),
+                              false /* isAnimationTainted */,
+                              true /* needsVariableResolution */),
+      *StrictCSSParserContext());
 }
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.cpp b/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.cpp
index c8d1504..6bf40d488 100644
--- a/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.cpp
+++ b/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.cpp
@@ -172,7 +172,8 @@
   if (CSSVariableParser::ContainsValidVariableReferences(original_range)) {
     bool is_animation_tainted = false;
     CSSVariableReferenceValue* variable = CSSVariableReferenceValue::Create(
-        CSSVariableData::Create(original_range, is_animation_tainted, true));
+        CSSVariableData::Create(original_range, is_animation_tainted, true),
+        *context_);
 
     if (is_shorthand) {
       const CSSPendingSubstitutionValue& pending_value =
diff --git a/third_party/WebKit/Source/core/css/parser/CSSVariableParser.cpp b/third_party/WebKit/Source/core/css/parser/CSSVariableParser.cpp
index d1e2b55..367fe981 100644
--- a/third_party/WebKit/Source/core/css/parser/CSSVariableParser.cpp
+++ b/third_party/WebKit/Source/core/css/parser/CSSVariableParser.cpp
@@ -154,6 +154,7 @@
 
 CSSVariableReferenceValue* CSSVariableParser::ParseRegisteredPropertyValue(
     CSSParserTokenRange range,
+    const CSSParserContext& context,
     bool require_var_reference,
     bool is_animation_tainted) {
   if (range.AtEnd())
@@ -170,7 +171,8 @@
     return nullptr;
   // TODO(timloh): Should this be hasReferences || hasAtApplyRule?
   return CSSVariableReferenceValue::Create(
-      CSSVariableData::Create(range, is_animation_tainted, has_references));
+      CSSVariableData::Create(range, is_animation_tainted, has_references),
+      context);
 }
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/css/parser/CSSVariableParser.h b/third_party/WebKit/Source/core/css/parser/CSSVariableParser.h
index 807de16..75a84196 100644
--- a/third_party/WebKit/Source/core/css/parser/CSSVariableParser.h
+++ b/third_party/WebKit/Source/core/css/parser/CSSVariableParser.h
@@ -14,6 +14,7 @@
 namespace blink {
 
 class CSSCustomPropertyDeclaration;
+class CSSParserContext;
 class CSSVariableReferenceValue;
 
 class CORE_EXPORT CSSVariableParser {
@@ -26,6 +27,7 @@
       bool is_animation_tainted);
   static CSSVariableReferenceValue* ParseRegisteredPropertyValue(
       CSSParserTokenRange,
+      const CSSParserContext&,
       bool require_var_reference,
       bool is_animation_tainted);
 
diff --git a/third_party/WebKit/Source/core/css/resolver/CSSVariableResolver.cpp b/third_party/WebKit/Source/core/css/resolver/CSSVariableResolver.cpp
index 941fd325..8b5e682 100644
--- a/third_party/WebKit/Source/core/css/resolver/CSSVariableResolver.cpp
+++ b/third_party/WebKit/Source/core/css/resolver/CSSVariableResolver.cpp
@@ -229,7 +229,7 @@
                                   is_animation_tainted))
     return CSSUnsetValue::Create();
   const CSSValue* result =
-      CSSPropertyParser::ParseSingleValue(id, tokens, StrictCSSParserContext());
+      CSSPropertyParser::ParseSingleValue(id, tokens, value.ParserContext());
   if (!result)
     return CSSUnsetValue::Create();
   return result;
@@ -258,13 +258,13 @@
     if (resolver.ResolveTokenRange(
             shorthand_value->VariableDataValue()->Tokens(),
             disallow_animation_tainted, tokens, is_animation_tainted)) {
-      CSSParserContext* context = CSSParserContext::Create(kHTMLStandardMode);
 
       HeapVector<CSSProperty, 256> parsed_properties;
 
       if (CSSPropertyParser::ParseValue(
               shorthand_property_id, false, CSSParserTokenRange(tokens),
-              context, parsed_properties, StyleRule::RuleType::kStyle)) {
+              shorthand_value->ParserContext(), parsed_properties,
+              StyleRule::RuleType::kStyle)) {
         unsigned parsed_properties_count = parsed_properties.size();
         for (unsigned i = 0; i < parsed_properties_count; ++i) {
           property_cache.Set(parsed_properties[i].Id(),
diff --git a/third_party/WebKit/Source/core/dom/ContainerNode.cpp b/third_party/WebKit/Source/core/dom/ContainerNode.cpp
index a28c419..6553bbdf 100644
--- a/third_party/WebKit/Source/core/dom/ContainerNode.cpp
+++ b/third_party/WebKit/Source/core/dom/ContainerNode.cpp
@@ -1316,32 +1316,49 @@
   }
 }
 
+void ContainerNode::RebuildLayoutTreeForChild(Node* child,
+                                              Text*& next_text_sibling) {
+  bool rebuild_child =
+      child->NeedsReattachLayoutTree() || child->ChildNeedsReattachLayoutTree();
+
+  if (child->IsTextNode()) {
+    Text* text_node = ToText(child);
+    if (rebuild_child)
+      text_node->RebuildTextLayoutTree(next_text_sibling);
+    next_text_sibling = text_node;
+    return;
+  }
+
+  if (!child->IsElementNode())
+    return;
+
+  Element* element = ToElement(child);
+  if (rebuild_child)
+    element->RebuildLayoutTree(next_text_sibling);
+  if (element->GetLayoutObject())
+    next_text_sibling = nullptr;
+}
+
 void ContainerNode::RebuildChildrenLayoutTrees(Text*& next_text_sibling) {
   DCHECK(!NeedsReattachLayoutTree());
 
+  if (IsActiveSlotOrActiveInsertionPoint()) {
+    if (isHTMLSlotElement(this))
+      toHTMLSlotElement(this)->RebuildDistributedChildrenLayoutTrees();
+    else
+      ToInsertionPoint(this)->RebuildDistributedChildrenLayoutTrees();
+  }
+
   // This loop is deliberately backwards because we use insertBefore in the
   // layout tree, and want to avoid a potentially n^2 loop to find the insertion
   // point while building the layout tree.  Having us start from the last child
   // and work our way back means in the common case, we'll find the insertion
   // point in O(1) time.  See crbug.com/288225
-  for (Node* child = lastChild(); child; child = child->previousSibling()) {
-    bool rebuild_child = child->NeedsReattachLayoutTree() ||
-                         child->ChildNeedsReattachLayoutTree();
-    if (child->IsTextNode()) {
-      Text* text_node = ToText(child);
-      if (rebuild_child)
-        text_node->RebuildTextLayoutTree(next_text_sibling);
-      next_text_sibling = text_node;
-    } else if (child->IsElementNode()) {
-      Element* element = ToElement(child);
-      if (rebuild_child)
-        element->RebuildLayoutTree(next_text_sibling);
-      if (element->GetLayoutObject())
-        next_text_sibling = nullptr;
-    }
-  }
-  // This is done in ContainerNode::attachLayoutTree but will never be cleared
-  // if we don't enter ContainerNode::attachLayoutTree so we do it here.
+  for (Node* child = lastChild(); child; child = child->previousSibling())
+    RebuildLayoutTreeForChild(child, next_text_sibling);
+
+  // This is done in ContainerNode::AttachLayoutTree but will never be cleared
+  // if we don't enter ContainerNode::AttachLayoutTree so we do it here.
   ClearChildNeedsStyleRecalc();
   ClearChildNeedsReattachLayoutTree();
 }
diff --git a/third_party/WebKit/Source/core/dom/ContainerNode.h b/third_party/WebKit/Source/core/dom/ContainerNode.h
index f398e46..2372f2ce 100644
--- a/third_party/WebKit/Source/core/dom/ContainerNode.h
+++ b/third_party/WebKit/Source/core/dom/ContainerNode.h
@@ -258,6 +258,7 @@
                                    Node* node_after_change);
   void RecalcDescendantStyles(StyleRecalcChange);
   void RebuildChildrenLayoutTrees(Text*& next_text_sibling);
+  void RebuildLayoutTreeForChild(Node* child, Text*& next_text_sibling);
 
   bool ChildrenSupportStyleSharing() const { return !HasRestyleFlags(); }
 
diff --git a/third_party/WebKit/Source/core/dom/Node.cpp b/third_party/WebKit/Source/core/dom/Node.cpp
index 7d8415f0..75a14c1 100644
--- a/third_party/WebKit/Source/core/dom/Node.cpp
+++ b/third_party/WebKit/Source/core/dom/Node.cpp
@@ -769,9 +769,27 @@
   GetDocument().ScheduleLayoutTreeUpdateIfNeeded();
 }
 
+static ContainerNode* GetReattachParent(Node& node) {
+  if (node.IsPseudoElement())
+    return node.ParentOrShadowHostNode();
+  if (node.IsChildOfV1ShadowHost()) {
+    if (HTMLSlotElement* slot = node.FinalDestinationSlot())
+      return slot;
+  }
+  if (node.IsInV0ShadowTree() || node.IsChildOfV0ShadowHost()) {
+    if (ShadowWhereNodeCanBeDistributedForV0(node)) {
+      if (InsertionPoint* insertion_point =
+              const_cast<InsertionPoint*>(ResolveReprojection(&node))) {
+        return insertion_point;
+      }
+    }
+  }
+  return node.ParentOrShadowHostNode();
+}
+
 void Node::MarkAncestorsWithChildNeedsReattachLayoutTree() {
-  for (ContainerNode* p = ParentOrShadowHostNode();
-       p && !p->ChildNeedsReattachLayoutTree(); p = p->ParentOrShadowHostNode())
+  for (ContainerNode* p = GetReattachParent(*this);
+       p && !p->ChildNeedsReattachLayoutTree(); p = GetReattachParent(*p))
     p->SetChildNeedsReattachLayoutTree();
 }
 
@@ -2391,6 +2409,17 @@
   return nullptr;
 }
 
+HTMLSlotElement* Node::FinalDestinationSlot() const {
+  HTMLSlotElement* slot = AssignedSlot();
+  if (!slot)
+    return nullptr;
+  for (HTMLSlotElement* next = slot->AssignedSlot(); next;
+       next = next->AssignedSlot()) {
+    slot = next;
+  }
+  return slot;
+}
+
 HTMLSlotElement* Node::assignedSlotForBinding() {
   // assignedSlot doesn't need to call updateDistribution().
   if (ShadowRoot* root = V1ShadowRootOfParent()) {
diff --git a/third_party/WebKit/Source/core/dom/Node.h b/third_party/WebKit/Source/core/dom/Node.h
index 259e7901..671a9e0 100644
--- a/third_party/WebKit/Source/core/dom/Node.h
+++ b/third_party/WebKit/Source/core/dom/Node.h
@@ -805,6 +805,7 @@
 
   StaticNodeList* getDestinationInsertionPoints();
   HTMLSlotElement* AssignedSlot() const;
+  HTMLSlotElement* FinalDestinationSlot() const;
   HTMLSlotElement* assignedSlotForBinding();
 
   bool IsFinishedParsingChildren() const {
diff --git a/third_party/WebKit/Source/core/dom/shadow/FlatTreeTraversal.cpp b/third_party/WebKit/Source/core/dom/shadow/FlatTreeTraversal.cpp
index 563d2ae..a8779c6 100644
--- a/third_party/WebKit/Source/core/dom/shadow/FlatTreeTraversal.cpp
+++ b/third_party/WebKit/Source/core/dom/shadow/FlatTreeTraversal.cpp
@@ -106,17 +106,6 @@
   return nullptr;
 }
 
-static HTMLSlotElement* FinalDestinationSlotFor(const Node& node) {
-  HTMLSlotElement* slot = node.AssignedSlot();
-  if (!slot)
-    return nullptr;
-  for (HTMLSlotElement* next = slot->AssignedSlot(); next;
-       next = next->AssignedSlot()) {
-    slot = next;
-  }
-  return slot;
-}
-
 // TODO(hayato): This may return a wrong result for a node which is not in a
 // document flat tree.  See FlatTreeTraversalTest's redistribution test for
 // details.
@@ -162,7 +151,7 @@
 Node* FlatTreeTraversal::TraverseSiblingsForV1HostChild(
     const Node& node,
     TraversalDirection direction) {
-  HTMLSlotElement* slot = FinalDestinationSlotFor(node);
+  HTMLSlotElement* slot = node.FinalDestinationSlot();
   if (!slot)
     return nullptr;
   if (Node* sibling_in_distributed_nodes =
@@ -195,7 +184,7 @@
     return node.ParentOrShadowHostNode();
 
   if (node.IsChildOfV1ShadowHost()) {
-    HTMLSlotElement* slot = FinalDestinationSlotFor(node);
+    HTMLSlotElement* slot = node.FinalDestinationSlot();
     if (!slot)
       return nullptr;
     return TraverseParent(*slot);
diff --git a/third_party/WebKit/Source/core/dom/shadow/InsertionPoint.cpp b/third_party/WebKit/Source/core/dom/shadow/InsertionPoint.cpp
index 394bb2a..788db882 100644
--- a/third_party/WebKit/Source/core/dom/shadow/InsertionPoint.cpp
+++ b/third_party/WebKit/Source/core/dom/shadow/InsertionPoint.cpp
@@ -121,6 +121,14 @@
   HTMLElement::DetachLayoutTree(context);
 }
 
+void InsertionPoint::RebuildDistributedChildrenLayoutTrees() {
+  Text* next_text_sibling = nullptr;
+  // This loop traverses the nodes from right to left for the same reason as the
+  // one described in ContainerNode::RebuildChildrenLayoutTrees().
+  for (size_t i = distributed_nodes_.size(); i > 0; --i)
+    RebuildLayoutTreeForChild(distributed_nodes_.at(i - 1), next_text_sibling);
+}
+
 void InsertionPoint::WillRecalcStyle(StyleRecalcChange change) {
   StyleChangeType style_change_type = kNoStyleChange;
 
diff --git a/third_party/WebKit/Source/core/dom/shadow/InsertionPoint.h b/third_party/WebKit/Source/core/dom/shadow/InsertionPoint.h
index fc20c3c..0d2e3cb8 100644
--- a/third_party/WebKit/Source/core/dom/shadow/InsertionPoint.h
+++ b/third_party/WebKit/Source/core/dom/shadow/InsertionPoint.h
@@ -58,6 +58,7 @@
 
   void AttachLayoutTree(const AttachContext& = AttachContext()) override;
   void DetachLayoutTree(const AttachContext& = AttachContext()) override;
+  void RebuildDistributedChildrenLayoutTrees();
 
   size_t DistributedNodesSize() const { return distributed_nodes_.size(); }
   Node* DistributedNodeAt(size_t index) const {
diff --git a/third_party/WebKit/Source/core/editing/CaretDisplayItemClientTest.cpp b/third_party/WebKit/Source/core/editing/CaretDisplayItemClientTest.cpp
index d2275e3..c783f12 100644
--- a/third_party/WebKit/Source/core/editing/CaretDisplayItemClientTest.cpp
+++ b/third_party/WebKit/Source/core/editing/CaretDisplayItemClientTest.cpp
@@ -95,7 +95,7 @@
   EXPECT_EQ(block->Location(), caret_visual_rect.Location());
 
   const auto* raster_invalidations =
-      &GetRasterInvalidationTracking()->tracked_raster_invalidations;
+      &GetRasterInvalidationTracking()->invalidations;
   ASSERT_EQ(1u, raster_invalidations->size());
   EXPECT_EQ(EnclosingIntRect(caret_visual_rect),
             (*raster_invalidations)[0].rect);
@@ -123,8 +123,7 @@
   EXPECT_EQ(caret_visual_rect.Y(), new_caret_visual_rect.Y());
   EXPECT_LT(caret_visual_rect.X(), new_caret_visual_rect.X());
 
-  raster_invalidations =
-      &GetRasterInvalidationTracking()->tracked_raster_invalidations;
+  raster_invalidations = &GetRasterInvalidationTracking()->invalidations;
   ASSERT_EQ(2u, raster_invalidations->size());
   EXPECT_EQ(EnclosingIntRect(caret_visual_rect),
             (*raster_invalidations)[0].rect);
@@ -150,8 +149,7 @@
   EXPECT_FALSE(block->ShouldPaintCursorCaret());
   EXPECT_EQ(LayoutRect(), GetCaretDisplayItemClient().VisualRect());
 
-  raster_invalidations =
-      &GetRasterInvalidationTracking()->tracked_raster_invalidations;
+  raster_invalidations = &GetRasterInvalidationTracking()->invalidations;
   ASSERT_EQ(1u, raster_invalidations->size());
   EXPECT_EQ(EnclosingIntRect(old_caret_visual_rect),
             (*raster_invalidations)[0].rect);
@@ -198,7 +196,7 @@
   EXPECT_TRUE(block2->ShouldPaintCursorCaret());
 
   const auto* raster_invalidations =
-      &GetRasterInvalidationTracking()->tracked_raster_invalidations;
+      &GetRasterInvalidationTracking()->invalidations;
   ASSERT_EQ(2u, raster_invalidations->size());
   EXPECT_EQ(EnclosingIntRect(caret_visual_rect1),
             (*raster_invalidations)[0].rect);
@@ -225,8 +223,7 @@
   EXPECT_TRUE(block1->ShouldPaintCursorCaret());
   EXPECT_FALSE(block2->ShouldPaintCursorCaret());
 
-  raster_invalidations =
-      &GetRasterInvalidationTracking()->tracked_raster_invalidations;
+  raster_invalidations = &GetRasterInvalidationTracking()->invalidations;
   ASSERT_EQ(2u, raster_invalidations->size());
   EXPECT_EQ(EnclosingIntRect(caret_visual_rect1),
             (*raster_invalidations)[0].rect);
@@ -331,7 +328,7 @@
   EXPECT_LT(caret_visual_rect.X(), new_caret_visual_rect.X());
 
   const auto& raster_invalidations =
-      GetRasterInvalidationTracking()->tracked_raster_invalidations;
+      GetRasterInvalidationTracking()->invalidations;
   ASSERT_EQ(2u, raster_invalidations.size());
   EXPECT_EQ(EnclosingIntRect(caret_visual_rect), raster_invalidations[0].rect);
   EXPECT_EQ(block, raster_invalidations[0].client);
diff --git a/third_party/WebKit/Source/core/frame/ImageBitmapTest.cpp b/third_party/WebKit/Source/core/frame/ImageBitmapTest.cpp
index 977ae00..30265b3 100644
--- a/third_party/WebKit/Source/core/frame/ImageBitmapTest.cpp
+++ b/third_party/WebKit/Source/core/frame/ImageBitmapTest.cpp
@@ -108,7 +108,7 @@
       HTMLImageElement::Create(*Document::Create());
   ImageResourceContent* image = ImageResourceContent::CreateLoaded(
       StaticBitmapImage::Create(image_).Get());
-  image_element->SetImageResource(image);
+  image_element->SetImageForTest(image);
 
   Optional<IntRect> crop_rect =
       IntRect(0, 0, image_->width(), image_->height());
@@ -151,7 +151,7 @@
   ImageResourceContent* original_image_resource =
       ImageResourceContent::CreateLoaded(
           StaticBitmapImage::Create(image_).Get());
-  image->SetImageResource(original_image_resource);
+  image->SetImageForTest(original_image_resource);
 
   const ImageBitmapOptions default_options;
   Optional<IntRect> crop_rect =
@@ -166,7 +166,7 @@
 
   ImageResourceContent* new_image_resource = ImageResourceContent::CreateLoaded(
       StaticBitmapImage::Create(image2_).Get());
-  image->SetImageResource(new_image_resource);
+  image->SetImageForTest(new_image_resource);
 
   {
     ASSERT_NE(image_bitmap->BitmapImage()->ImageForCurrentFrame(),
@@ -244,7 +244,7 @@
   ImageResourceContent* original_image_resource =
       ImageResourceContent::CreateLoaded(
           StaticBitmapImage::Create(image).Get());
-  image_element->SetImageResource(original_image_resource);
+  image_element->SetImageForTest(original_image_resource);
 
   Optional<IntRect> crop_rect = IntRect(0, 0, image->width(), image->height());
 
@@ -356,7 +356,7 @@
   ImageResourceContent* source_image_resource =
       ImageResourceContent::CreateLoaded(
           StaticBitmapImage::Create(image).Get());
-  image_element->SetImageResource(source_image_resource);
+  image_element->SetImageForTest(source_image_resource);
 
   Optional<IntRect> crop_rect = IntRect(0, 0, image->width(), image->height());
   ImageBitmapOptions options =
diff --git a/third_party/WebKit/Source/core/geometry/DOMMatrix.cpp b/third_party/WebKit/Source/core/geometry/DOMMatrix.cpp
index b87df83..13a2e3c 100644
--- a/third_party/WebKit/Source/core/geometry/DOMMatrix.cpp
+++ b/third_party/WebKit/Source/core/geometry/DOMMatrix.cpp
@@ -6,13 +6,21 @@
 
 namespace blink {
 
-DOMMatrix* DOMMatrix::Create(ExceptionState& exception_state) {
+DOMMatrix* DOMMatrix::Create(ExecutionContext* execution_context,
+                             ExceptionState& exception_state) {
   return new DOMMatrix(TransformationMatrix());
 }
 
-DOMMatrix* DOMMatrix::Create(StringOrUnrestrictedDoubleSequence& init,
+DOMMatrix* DOMMatrix::Create(ExecutionContext* execution_context,
+                             StringOrUnrestrictedDoubleSequence& init,
                              ExceptionState& exception_state) {
   if (init.isString()) {
+    if (!execution_context->IsDocument()) {
+      exception_state.ThrowTypeError(
+          "DOMMatrix can't be constructed with strings on workers.");
+      return nullptr;
+    }
+
     DOMMatrix* matrix = new DOMMatrix(TransformationMatrix());
     matrix->SetMatrixValueFromString(init.getAsString(), exception_state);
     return matrix;
diff --git a/third_party/WebKit/Source/core/geometry/DOMMatrix.h b/third_party/WebKit/Source/core/geometry/DOMMatrix.h
index e809cd5a..6efa808 100644
--- a/third_party/WebKit/Source/core/geometry/DOMMatrix.h
+++ b/third_party/WebKit/Source/core/geometry/DOMMatrix.h
@@ -17,8 +17,9 @@
   DEFINE_WRAPPERTYPEINFO();
 
  public:
-  static DOMMatrix* Create(ExceptionState&);
-  static DOMMatrix* Create(StringOrUnrestrictedDoubleSequence&,
+  static DOMMatrix* Create(ExecutionContext*, ExceptionState&);
+  static DOMMatrix* Create(ExecutionContext*,
+                           StringOrUnrestrictedDoubleSequence&,
                            ExceptionState&);
   // TODO(fserb): double check those two bellow are needed:
   static DOMMatrix* Create(DOMMatrixReadOnly*,
diff --git a/third_party/WebKit/Source/core/geometry/DOMMatrix.idl b/third_party/WebKit/Source/core/geometry/DOMMatrix.idl
index 49f6c93..7da60c0 100644
--- a/third_party/WebKit/Source/core/geometry/DOMMatrix.idl
+++ b/third_party/WebKit/Source/core/geometry/DOMMatrix.idl
@@ -7,6 +7,7 @@
 [
     Constructor(optional (DOMString or sequence<unrestricted double>) init),
     RaisesException=Constructor,
+    ConstructorCallWith=ExecutionContext,
     Exposed=(Window,Worker),
     RuntimeEnabled=GeometryInterfaces,
 ] interface DOMMatrix : DOMMatrixReadOnly {
diff --git a/third_party/WebKit/Source/core/geometry/DOMMatrixReadOnly.cpp b/third_party/WebKit/Source/core/geometry/DOMMatrixReadOnly.cpp
index 876729c9..b7e45a2 100644
--- a/third_party/WebKit/Source/core/geometry/DOMMatrixReadOnly.cpp
+++ b/third_party/WebKit/Source/core/geometry/DOMMatrixReadOnly.cpp
@@ -92,14 +92,23 @@
   return true;
 }
 
-DOMMatrixReadOnly* DOMMatrixReadOnly::Create(ExceptionState& exception_state) {
+DOMMatrixReadOnly* DOMMatrixReadOnly::Create(
+    ExecutionContext* execution_context,
+    ExceptionState& exception_state) {
   return new DOMMatrixReadOnly(TransformationMatrix());
 }
 
 DOMMatrixReadOnly* DOMMatrixReadOnly::Create(
+    ExecutionContext* execution_context,
     StringOrUnrestrictedDoubleSequence& init,
     ExceptionState& exception_state) {
   if (init.isString()) {
+    if (!execution_context->IsDocument()) {
+      exception_state.ThrowTypeError(
+          "DOMMatrix can't be constructed with strings on workers.");
+      return nullptr;
+    }
+
     DOMMatrixReadOnly* matrix = new DOMMatrixReadOnly(TransformationMatrix());
     matrix->SetMatrixValueFromString(init.getAsString(), exception_state);
     return matrix;
diff --git a/third_party/WebKit/Source/core/geometry/DOMMatrixReadOnly.h b/third_party/WebKit/Source/core/geometry/DOMMatrixReadOnly.h
index 10ae70a0..05f7f33 100644
--- a/third_party/WebKit/Source/core/geometry/DOMMatrixReadOnly.h
+++ b/third_party/WebKit/Source/core/geometry/DOMMatrixReadOnly.h
@@ -27,8 +27,9 @@
   DEFINE_WRAPPERTYPEINFO();
 
  public:
-  static DOMMatrixReadOnly* Create(ExceptionState&);
-  static DOMMatrixReadOnly* Create(StringOrUnrestrictedDoubleSequence&,
+  static DOMMatrixReadOnly* Create(ExecutionContext*, ExceptionState&);
+  static DOMMatrixReadOnly* Create(ExecutionContext*,
+                                   StringOrUnrestrictedDoubleSequence&,
                                    ExceptionState&);
   static DOMMatrixReadOnly* fromFloat32Array(NotShared<DOMFloat32Array>,
                                              ExceptionState&);
diff --git a/third_party/WebKit/Source/core/geometry/DOMMatrixReadOnly.idl b/third_party/WebKit/Source/core/geometry/DOMMatrixReadOnly.idl
index 755a208..1032f29 100644
--- a/third_party/WebKit/Source/core/geometry/DOMMatrixReadOnly.idl
+++ b/third_party/WebKit/Source/core/geometry/DOMMatrixReadOnly.idl
@@ -7,6 +7,7 @@
 [
     Constructor(optional (DOMString or sequence<unrestricted double>) init),
     RaisesException=Constructor,
+    ConstructorCallWith=ExecutionContext,
     Exposed=(Window,Worker),
     RuntimeEnabled=GeometryInterfaces,
 ] interface DOMMatrixReadOnly {
diff --git a/third_party/WebKit/Source/core/html/HTMLImageElement.h b/third_party/WebKit/Source/core/html/HTMLImageElement.h
index 429a0bce..6caecfa 100644
--- a/third_party/WebKit/Source/core/html/HTMLImageElement.h
+++ b/third_party/WebKit/Source/core/html/HTMLImageElement.h
@@ -83,8 +83,8 @@
   ImageResource* CachedImageResourceForImageDocument() const {
     return GetImageLoader().ImageResourceForImageDocument();
   }
-  void SetImageResource(ImageResourceContent* i) {
-    GetImageLoader().SetImage(i);
+  void SetImageForTest(ImageResourceContent* content) {
+    GetImageLoader().SetImageForTest(content);
   }
 
   void SetLoadingImageDocument() { GetImageLoader().SetLoadingImageDocument(); }
diff --git a/third_party/WebKit/Source/core/html/HTMLObjectElement.cpp b/third_party/WebKit/Source/core/html/HTMLObjectElement.cpp
index f17c71f..4cdbe2a0e 100644
--- a/third_party/WebKit/Source/core/html/HTMLObjectElement.cpp
+++ b/third_party/WebKit/Source/core/html/HTMLObjectElement.cpp
@@ -399,7 +399,7 @@
     if (!IsImageType()) {
       // If we don't think we have an image type anymore, then clear the image
       // from the loader.
-      image_loader_->SetImage(0);
+      image_loader_->ClearImage();
       ReattachFallbackContent();
       return;
     }
diff --git a/third_party/WebKit/Source/core/html/HTMLSlotElement.cpp b/third_party/WebKit/Source/core/html/HTMLSlotElement.cpp
index beb514f..12eec94 100644
--- a/third_party/WebKit/Source/core/html/HTMLSlotElement.cpp
+++ b/third_party/WebKit/Source/core/html/HTMLSlotElement.cpp
@@ -200,6 +200,18 @@
   HTMLElement::DetachLayoutTree(context);
 }
 
+void HTMLSlotElement::RebuildDistributedChildrenLayoutTrees() {
+  if (!SupportsDistribution())
+    return;
+  Text* next_text_sibling = nullptr;
+  // This loop traverses the nodes from right to left for the same reason as the
+  // one described in ContainerNode::RebuildChildrenLayoutTrees().
+  for (auto it = distributed_nodes_.rbegin(); it != distributed_nodes_.rend();
+       ++it) {
+    RebuildLayoutTreeForChild(*it, next_text_sibling);
+  }
+}
+
 void HTMLSlotElement::AttributeChanged(
     const AttributeModificationParams& params) {
   if (params.name == nameAttr) {
diff --git a/third_party/WebKit/Source/core/html/HTMLSlotElement.h b/third_party/WebKit/Source/core/html/HTMLSlotElement.h
index eef9450..dffa5dfc 100644
--- a/third_party/WebKit/Source/core/html/HTMLSlotElement.h
+++ b/third_party/WebKit/Source/core/html/HTMLSlotElement.h
@@ -76,6 +76,7 @@
 
   void AttachLayoutTree(const AttachContext& = AttachContext()) final;
   void DetachLayoutTree(const AttachContext& = AttachContext()) final;
+  void RebuildDistributedChildrenLayoutTrees();
 
   void AttributeChanged(const AttributeModificationParams&) final;
 
diff --git a/third_party/WebKit/Source/core/html/HTMLVideoElement.cpp b/third_party/WebKit/Source/core/html/HTMLVideoElement.cpp
index 51a54c41..a3466a0 100644
--- a/third_party/WebKit/Source/core/html/HTMLVideoElement.cpp
+++ b/third_party/WebKit/Source/core/html/HTMLVideoElement.cpp
@@ -317,17 +317,20 @@
 
 bool HTMLVideoElement::CopyVideoTextureToPlatformTexture(
     gpu::gles2::GLES2Interface* gl,
+    GLenum target,
     GLuint texture,
     GLenum internal_format,
     GLenum format,
     GLenum type,
+    GLint level,
     bool premultiply_alpha,
     bool flip_y) {
   if (!GetWebMediaPlayer())
     return false;
 
   return GetWebMediaPlayer()->CopyVideoTextureToPlatformTexture(
-      gl, texture, internal_format, format, type, premultiply_alpha, flip_y);
+      gl, target, texture, internal_format, format, type, level,
+      premultiply_alpha, flip_y);
 }
 
 bool HTMLVideoElement::TexImageImpl(
diff --git a/third_party/WebKit/Source/core/html/HTMLVideoElement.h b/third_party/WebKit/Source/core/html/HTMLVideoElement.h
index a956e36c..6c9a1f55 100644
--- a/third_party/WebKit/Source/core/html/HTMLVideoElement.h
+++ b/third_party/WebKit/Source/core/html/HTMLVideoElement.h
@@ -79,10 +79,12 @@
 
   // Used by WebGL to do GPU-GPU textures copy if possible.
   bool CopyVideoTextureToPlatformTexture(gpu::gles2::GLES2Interface*,
+                                         GLenum target,
                                          GLuint texture,
                                          GLenum internal_format,
                                          GLenum format,
                                          GLenum type,
+                                         GLint level,
                                          bool premultiply_alpha,
                                          bool flip_y);
 
diff --git a/third_party/WebKit/Source/core/layout/LayoutBoxModelObject.h b/third_party/WebKit/Source/core/layout/LayoutBoxModelObject.h
index f3bbba2..cd43aa2 100644
--- a/third_party/WebKit/Source/core/layout/LayoutBoxModelObject.h
+++ b/third_party/WebKit/Source/core/layout/LayoutBoxModelObject.h
@@ -286,6 +286,11 @@
   LayoutUnit BorderWidth() const { return BorderLeft() + BorderRight(); }
   LayoutUnit BorderHeight() const { return BorderTop() + BorderBottom(); }
 
+  virtual LayoutRectOutsets BorderBoxOutsets() const {
+    return LayoutRectOutsets(BorderTop(), BorderRight(), BorderBottom(),
+                             BorderLeft());
+  }
+
   // Insets from the border box to the inside of the border.
   LayoutRectOutsets BorderInsets() const {
     return LayoutRectOutsets(-BorderTop(), -BorderRight(), -BorderBottom(),
diff --git a/third_party/WebKit/Source/core/layout/compositing/CompositedLayerMapping.cpp b/third_party/WebKit/Source/core/layout/compositing/CompositedLayerMapping.cpp
index ca181cf..0b87b6a 100644
--- a/third_party/WebKit/Source/core/layout/compositing/CompositedLayerMapping.cpp
+++ b/third_party/WebKit/Source/core/layout/compositing/CompositedLayerMapping.cpp
@@ -3417,7 +3417,7 @@
   DrawingRecorder drawing_recorder(context, *graphics_layer,
                                    DisplayItem::kScrollbarCompositedScrollbar,
                                    layer_bounds);
-  context.Canvas()->PlaybackPaintRecord(builder.EndRecording());
+  context.Canvas()->drawPicture(builder.EndRecording());
 }
 
 bool CompositedLayerMapping::IsScrollableAreaLayer(
diff --git a/third_party/WebKit/Source/core/layout/compositing/CompositingReasonFinder.cpp b/third_party/WebKit/Source/core/layout/compositing/CompositingReasonFinder.cpp
index 5e53c85..1050d0e7 100644
--- a/third_party/WebKit/Source/core/layout/compositing/CompositingReasonFinder.cpp
+++ b/third_party/WebKit/Source/core/layout/compositing/CompositingReasonFinder.cpp
@@ -147,7 +147,7 @@
   CompositingReasons direct_reasons = kCompositingReasonNone;
   LayoutObject& layout_object = layer->GetLayoutObject();
 
-  if (compositing_triggers_ & kOverflowScrollTrigger && layer->ClipParent())
+  if (layer->ClipParent())
     direct_reasons |= kCompositingReasonOutOfFlowClipping;
 
   if (layer->NeedsCompositedScrolling())
diff --git a/third_party/WebKit/Source/core/layout/compositing/PaintLayerCompositor.cpp b/third_party/WebKit/Source/core/layout/compositing/PaintLayerCompositor.cpp
index 5bd2202..ac75be41 100644
--- a/third_party/WebKit/Source/core/layout/compositing/PaintLayerCompositor.cpp
+++ b/third_party/WebKit/Source/core/layout/compositing/PaintLayerCompositor.cpp
@@ -971,7 +971,7 @@
   DrawingRecorder drawing_recorder(context, *graphics_layer,
                                    DisplayItem::kScrollbarCompositedScrollbar,
                                    layer_bounds);
-  context.Canvas()->PlaybackPaintRecord(builder.EndRecording());
+  context.Canvas()->drawPicture(builder.EndRecording());
 }
 
 Scrollbar* PaintLayerCompositor::GraphicsLayerToScrollbar(
diff --git a/third_party/WebKit/Source/core/loader/ImageLoader.cpp b/third_party/WebKit/Source/core/loader/ImageLoader.cpp
index 9e5ab6a..5421719 100644
--- a/third_party/WebKit/Source/core/loader/ImageLoader.cpp
+++ b/third_party/WebKit/Source/core/loader/ImageLoader.cpp
@@ -186,7 +186,8 @@
   visitor->Trace(element_);
 }
 
-void ImageLoader::SetImage(ImageResourceContent* new_image) {
+void ImageLoader::SetImageForTest(ImageResourceContent* new_image) {
+  DCHECK(new_image);
   SetImageWithoutConsideringPendingLoadEvent(new_image);
 
   // Only consider updating the protection ref-count of the Element immediately
@@ -195,12 +196,40 @@
   UpdatedHasPendingEvent();
 }
 
+void ImageLoader::ClearImage() {
+  SetImageWithoutConsideringPendingLoadEvent(nullptr);
+
+  // Only consider updating the protection ref-count of the Element immediately
+  // before returning from this function as doing so might result in the
+  // destruction of this ImageLoader.
+  UpdatedHasPendingEvent();
+}
+
+void ImageLoader::SetImageForImageDocument(ImageResource* new_image_resource) {
+  DCHECK(loading_image_document_);
+  DCHECK(new_image_resource);
+  DCHECK(new_image_resource->GetContent());
+
+  image_resource_for_image_document_ = new_image_resource;
+  SetImageWithoutConsideringPendingLoadEvent(new_image_resource->GetContent());
+
+  // |has_pending_load_event_| is always false and |image_complete_| is
+  // always true for ImageDocument loading, while the loading is just started.
+  // TODO(hiroshige): clean up the behavior of flags. https://crbug.com/719759
+  has_pending_load_event_ = false;
+  image_complete_ = true;
+
+  // Only consider updating the protection ref-count of the Element immediately
+  // before returning from this function as doing so might result in the
+  // destruction of this ImageLoader.
+  UpdatedHasPendingEvent();
+}
+
 void ImageLoader::SetImageWithoutConsideringPendingLoadEvent(
     ImageResourceContent* new_image) {
   DCHECK(failed_load_url_.IsEmpty());
   ImageResourceContent* old_image = image_.Get();
   if (new_image != old_image) {
-    image_ = new_image;
     if (has_pending_load_event_) {
       LoadEventSender().CancelEvent(this);
       has_pending_load_event_ = false;
@@ -209,7 +238,7 @@
       ErrorEventSender().CancelEvent(this);
       has_pending_error_event_ = false;
     }
-    image_complete_ = true;
+    UpdateImageState(new_image);
     if (new_image) {
       new_image->AddObserver(this);
     }
@@ -268,6 +297,12 @@
       IncrementLoadEventDelayCount::Create(element_->GetDocument());
 }
 
+void ImageLoader::UpdateImageState(ImageResourceContent* new_image) {
+  image_ = new_image;
+  has_pending_load_event_ = new_image;
+  image_complete_ = !new_image;
+}
+
 void ImageLoader::DoUpdateFromElement(BypassMainWorldBehavior bypass_behavior,
                                       UpdateFromElementBehavior update_behavior,
                                       const KURL& url,
@@ -356,9 +391,7 @@
       has_pending_error_event_ = false;
     }
 
-    image_ = new_image;
-    has_pending_load_event_ = new_image;
-    image_complete_ = !new_image;
+    UpdateImageState(new_image);
 
     UpdateLayoutObject();
     // If newImage exists and is cached, addObserver() will result in the load
@@ -402,8 +435,7 @@
         ResourceRequest(ImageSourceToKURL(element_->ImageSourceURL())));
     image_resource->SetStatus(ResourceStatus::kPending);
     image_resource->NotifyStartLoad();
-    image_resource_for_image_document_ = image_resource;
-    SetImage(image_resource->GetContent());
+    SetImageForImageDocument(image_resource);
     return;
   }
 
@@ -639,7 +671,7 @@
   if (load_delay_counter_)
     load_delay_counter_->DocumentChanged(element_->GetDocument());
   ClearFailedLoadURL();
-  SetImage(0);
+  ClearImage();
 }
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/loader/ImageLoader.h b/third_party/WebKit/Source/core/loader/ImageLoader.h
index f0cf0fe..eb5c656 100644
--- a/third_party/WebKit/Source/core/loader/ImageLoader.h
+++ b/third_party/WebKit/Source/core/loader/ImageLoader.h
@@ -89,8 +89,13 @@
   ImageResource* ImageResourceForImageDocument() const {
     return image_resource_for_image_document_;
   }
+
   // Cancels pending load events, and doesn't dispatch new ones.
-  void SetImage(ImageResourceContent*);
+  // Note: ClearImage/SetImage.*() are not a simple setter.
+  // Check the implementation to see what they do.
+  // TODO(hiroshige): Cleanup these methods.
+  void ClearImage();
+  void SetImageForTest(ImageResourceContent*);
 
   bool IsLoadingImageDocument() { return loading_image_document_; }
   void SetLoadingImageDocument() { loading_image_document_ = true; }
@@ -133,7 +138,13 @@
   LayoutImageResource* GetLayoutImageResource();
   void UpdateLayoutObject();
 
+  // Note: SetImage.*() are not a simple setter.
+  // Check the implementation to see what they do.
+  // TODO(hiroshige): Cleanup these methods.
+  void SetImageForImageDocument(ImageResource*);
   void SetImageWithoutConsideringPendingLoadEvent(ImageResourceContent*);
+  void UpdateImageState(ImageResourceContent*);
+
   void ClearFailedLoadURL();
   void DispatchErrorEvent();
   void CrossSiteOrCSPViolationOccurred(AtomicString);
diff --git a/third_party/WebKit/Source/core/paint/BoxPaintInvalidatorTest.cpp b/third_party/WebKit/Source/core/paint/BoxPaintInvalidatorTest.cpp
index d0503634..2cdf5646 100644
--- a/third_party/WebKit/Source/core/paint/BoxPaintInvalidatorTest.cpp
+++ b/third_party/WebKit/Source/core/paint/BoxPaintInvalidatorTest.cpp
@@ -75,7 +75,7 @@
   target->setAttribute(HTMLNames::styleAttr, "width: 100px; height: 200px");
   GetDocument().View()->UpdateAllLifecyclePhases();
   const auto& raster_invalidations =
-      GetRasterInvalidationTracking()->tracked_raster_invalidations;
+      GetRasterInvalidationTracking()->invalidations;
   ASSERT_EQ(2u, raster_invalidations.size());
   EXPECT_EQ(IntRect(60, 0, 60, 240), raster_invalidations[0].rect);
   EXPECT_EQ(kPaintInvalidationIncremental, raster_invalidations[0].reason);
@@ -90,7 +90,7 @@
   target->setAttribute(HTMLNames::styleAttr, "width: 20px; height: 80px");
   GetDocument().View()->UpdateAllLifecyclePhases();
   const auto& raster_invalidations =
-      GetRasterInvalidationTracking()->tracked_raster_invalidations;
+      GetRasterInvalidationTracking()->invalidations;
   ASSERT_EQ(2u, raster_invalidations.size());
   EXPECT_EQ(IntRect(30, 0, 40, 140), raster_invalidations[0].rect);
   EXPECT_EQ(kPaintInvalidationIncremental, raster_invalidations[0].reason);
@@ -105,7 +105,7 @@
   target->setAttribute(HTMLNames::styleAttr, "width: 100px; height: 80px");
   GetDocument().View()->UpdateAllLifecyclePhases();
   const auto& raster_invalidations =
-      GetRasterInvalidationTracking()->tracked_raster_invalidations;
+      GetRasterInvalidationTracking()->invalidations;
   ASSERT_EQ(2u, raster_invalidations.size());
   EXPECT_EQ(IntRect(60, 0, 60, 120), raster_invalidations[0].rect);
   EXPECT_EQ(kPaintInvalidationIncremental, raster_invalidations[0].reason);
@@ -124,7 +124,7 @@
   target->setAttribute(HTMLNames::styleAttr, "width: 100.6px; height: 70.3px");
   GetDocument().View()->UpdateAllLifecyclePhases();
   const auto* raster_invalidations =
-      &GetRasterInvalidationTracking()->tracked_raster_invalidations;
+      &GetRasterInvalidationTracking()->invalidations;
   ASSERT_EQ(2u, raster_invalidations->size());
   EXPECT_EQ(IntRect(60, 0, 61, 111), (*raster_invalidations)[0].rect);
   EXPECT_EQ(kPaintInvalidationIncremental, (*raster_invalidations)[0].reason);
@@ -135,8 +135,7 @@
   GetDocument().View()->SetTracksPaintInvalidations(true);
   target->setAttribute(HTMLNames::styleAttr, "width: 50px; height: 100px");
   GetDocument().View()->UpdateAllLifecyclePhases();
-  raster_invalidations =
-      &GetRasterInvalidationTracking()->tracked_raster_invalidations;
+  raster_invalidations = &GetRasterInvalidationTracking()->invalidations;
   ASSERT_EQ(2u, raster_invalidations->size());
   EXPECT_EQ(IntRect(60, 0, 61, 111), (*raster_invalidations)[0].rect);
   EXPECT_EQ(kPaintInvalidationIncremental, (*raster_invalidations)[0].reason);
@@ -157,7 +156,7 @@
   target->setAttribute(HTMLNames::styleAttr, "width: 100.6px; height: 70.3px");
   GetDocument().View()->UpdateAllLifecyclePhases();
   const auto* raster_invalidations =
-      &GetRasterInvalidationTracking()->tracked_raster_invalidations;
+      &GetRasterInvalidationTracking()->invalidations;
   ASSERT_EQ(2u, raster_invalidations->size());
   EXPECT_EQ(IntRect(0, 0, 140, 280), (*raster_invalidations)[0].rect);
   EXPECT_EQ(kPaintInvalidationBorderBoxChange,
@@ -170,8 +169,7 @@
   GetDocument().View()->SetTracksPaintInvalidations(true);
   target->setAttribute(HTMLNames::styleAttr, "width: 50px; height: 100px");
   GetDocument().View()->UpdateAllLifecyclePhases();
-  raster_invalidations =
-      &GetRasterInvalidationTracking()->tracked_raster_invalidations;
+  raster_invalidations = &GetRasterInvalidationTracking()->invalidations;
   ASSERT_EQ(2u, raster_invalidations->size());
   EXPECT_EQ(IntRect(0, 0, 242, 222), (*raster_invalidations)[0].rect);
   EXPECT_EQ(kPaintInvalidationBorderBoxChange,
@@ -198,7 +196,7 @@
                        LayoutUnit(139.3)),
             target_object->VisualRect());
   const auto* raster_invalidations =
-      &GetRasterInvalidationTracking()->tracked_raster_invalidations;
+      &GetRasterInvalidationTracking()->invalidations;
   ASSERT_EQ(1u, raster_invalidations->size());
   EXPECT_EQ(IntRect(0, 0, 70, 140), (*raster_invalidations)[0].rect);
   EXPECT_EQ(kPaintInvalidationBoundsChange, (*raster_invalidations)[0].reason);
@@ -211,8 +209,7 @@
   EXPECT_EQ(LayoutRect(LayoutUnit(), LayoutUnit(0.6), LayoutUnit(69.3),
                        LayoutUnit(138.5)),
             target_object->VisualRect());
-  raster_invalidations =
-      &GetRasterInvalidationTracking()->tracked_raster_invalidations;
+  raster_invalidations = &GetRasterInvalidationTracking()->invalidations;
   ASSERT_EQ(2u, raster_invalidations->size());
   EXPECT_EQ(IntRect(59, 0, 11, 140), (*raster_invalidations)[0].rect);
   EXPECT_EQ(kPaintInvalidationIncremental, (*raster_invalidations)[0].reason);
@@ -235,7 +232,7 @@
                        "transform: rotate(45deg); width: 200px");
   GetDocument().View()->UpdateAllLifecyclePhases();
   const auto* raster_invalidations =
-      &GetRasterInvalidationTracking()->tracked_raster_invalidations;
+      &GetRasterInvalidationTracking()->invalidations;
   ASSERT_EQ(1u, raster_invalidations->size());
   EXPECT_EQ(IntRect(-99, 0, 255, 255), (*raster_invalidations)[0].rect);
   EXPECT_EQ(kPaintInvalidationBorderBoxChange,
@@ -262,7 +259,7 @@
                       "width: 100px; height: 50px; background: red");
   GetDocument().View()->UpdateAllLifecyclePhases();
   const auto* raster_invalidations =
-      &GetRasterInvalidationTracking()->tracked_raster_invalidations;
+      &GetRasterInvalidationTracking()->invalidations;
   ASSERT_EQ(1u, raster_invalidations->size());
   EXPECT_EQ(IntRect(-43, 21, 107, 107), (*raster_invalidations)[0].rect);
   EXPECT_EQ(kPaintInvalidationBorderBoxChange,
@@ -282,7 +279,7 @@
   target->setAttribute(HTMLNames::styleAttr, "height: 3000px");
   GetDocument().View()->UpdateAllLifecyclePhases();
   const auto& raster_invalidations =
-      GetRasterInvalidationTracking()->tracked_raster_invalidations;
+      GetRasterInvalidationTracking()->invalidations;
   ASSERT_EQ(1u, raster_invalidations.size());
   EXPECT_EQ(IntRect(0, 2000, 800, 1000), raster_invalidations[0].rect);
   EXPECT_EQ(static_cast<const DisplayItemClient*>(&GetLayoutView()),
@@ -318,7 +315,7 @@
   GetDocument().View()->UpdateAllLifecyclePhases();
 
   const auto& raster_invalidations =
-      GetRasterInvalidationTracking()->tracked_raster_invalidations;
+      GetRasterInvalidationTracking()->invalidations;
   ASSERT_EQ(1u, raster_invalidations.size());
   EXPECT_EQ(IntRect(0, 0, 800, 3000), raster_invalidations[0].rect);
   EXPECT_EQ(static_cast<const DisplayItemClient*>(&GetLayoutView()),
@@ -373,7 +370,7 @@
   iframe->setAttribute(HTMLNames::styleAttr, "height: 200px");
   GetDocument().View()->UpdateAllLifecyclePhases();
   const auto& raster_invalidations =
-      GetRasterInvalidationTracking()->tracked_raster_invalidations;
+      GetRasterInvalidationTracking()->invalidations;
   ASSERT_EQ(2u, raster_invalidations.size());
   EXPECT_EQ(IntRect(0, 100, 100, 100), raster_invalidations[0].rect);
   EXPECT_EQ(static_cast<const DisplayItemClient*>(iframe->GetLayoutObject()),
@@ -423,7 +420,7 @@
   content->setAttribute(HTMLNames::styleAttr, "height: 500px");
   GetDocument().View()->UpdateAllLifecyclePhases();
   const auto* raster_invalidations =
-      &GetRasterInvalidationTracking()->tracked_raster_invalidations;
+      &GetRasterInvalidationTracking()->invalidations;
   ASSERT_EQ(1u, raster_invalidations->size());
   EXPECT_EQ(IntRect(0, 0, 100, 100), (*raster_invalidations)[0].rect);
   EXPECT_EQ(static_cast<const DisplayItemClient*>(frame_layout_view),
@@ -436,8 +433,7 @@
   GetDocument().View()->SetTracksPaintInvalidations(true);
   iframe->setAttribute(HTMLNames::styleAttr, "height: 200px");
   GetDocument().View()->UpdateAllLifecyclePhases();
-  raster_invalidations =
-      &GetRasterInvalidationTracking()->tracked_raster_invalidations;
+  raster_invalidations = &GetRasterInvalidationTracking()->invalidations;
   ASSERT_EQ(2u, raster_invalidations->size());
   EXPECT_EQ(IntRect(0, 100, 100, 100), (*raster_invalidations)[0].rect);
   EXPECT_EQ(static_cast<const DisplayItemClient*>(iframe->GetLayoutObject()),
@@ -482,8 +478,7 @@
   EXPECT_FALSE(container_layer->GetRasterInvalidationTracking());
   // Incremental invalidation of background on contents layer.
   const auto& contents_raster_invalidations =
-      contents_layer->GetRasterInvalidationTracking()
-          ->tracked_raster_invalidations;
+      contents_layer->GetRasterInvalidationTracking()->invalidations;
   ASSERT_EQ(1u, contents_raster_invalidations.size());
   EXPECT_EQ(IntRect(0, 500, 500, 500), contents_raster_invalidations[0].rect);
   EXPECT_EQ(static_cast<const DisplayItemClient*>(target->GetLayoutObject()),
@@ -501,8 +496,7 @@
   EXPECT_FALSE(contents_layer->GetRasterInvalidationTracking());
   // Incremental invalidation on the container layer.
   const auto& container_raster_invalidations =
-      container_layer->GetRasterInvalidationTracking()
-          ->tracked_raster_invalidations;
+      container_layer->GetRasterInvalidationTracking()->invalidations;
   ASSERT_EQ(1u, container_raster_invalidations.size());
   EXPECT_EQ(IntRect(0, 120, 70, 120), container_raster_invalidations[0].rect);
   EXPECT_EQ(static_cast<const DisplayItemClient*>(target->GetLayoutObject()),
@@ -540,8 +534,7 @@
   // Full invalidation of background on contents layer because the gradient
   // background is resized.
   const auto& contents_raster_invalidations =
-      contents_layer->GetRasterInvalidationTracking()
-          ->tracked_raster_invalidations;
+      contents_layer->GetRasterInvalidationTracking()->invalidations;
   ASSERT_EQ(1u, contents_raster_invalidations.size());
   EXPECT_EQ(IntRect(0, 0, 500, 1000), contents_raster_invalidations[0].rect);
   EXPECT_EQ(static_cast<const DisplayItemClient*>(target->GetLayoutObject()),
@@ -558,8 +551,7 @@
   EXPECT_FALSE(contents_layer->GetRasterInvalidationTracking());
   // Full invalidation on the container layer.
   const auto& container_raster_invalidations =
-      container_layer->GetRasterInvalidationTracking()
-          ->tracked_raster_invalidations;
+      container_layer->GetRasterInvalidationTracking()->invalidations;
   ASSERT_EQ(1u, container_raster_invalidations.size());
   EXPECT_EQ(IntRect(0, 0, 70, 240), container_raster_invalidations[0].rect);
   EXPECT_EQ(static_cast<const DisplayItemClient*>(target->GetLayoutObject()),
@@ -592,7 +584,7 @@
   target->setAttribute(HTMLNames::styleAttr, "height: 200px");
   GetDocument().View()->UpdateAllLifecyclePhases();
   const auto& raster_invalidations =
-      GetRasterInvalidationTracking()->tracked_raster_invalidations;
+      GetRasterInvalidationTracking()->invalidations;
   ASSERT_EQ(1u, raster_invalidations.size());
   EXPECT_EQ(IntRect(0, 120, 70, 120), raster_invalidations[0].rect);
   EXPECT_EQ(static_cast<const DisplayItemClient*>(target->GetLayoutObject()),
diff --git a/third_party/WebKit/Source/core/paint/BoxPainter.cpp b/third_party/WebKit/Source/core/paint/BoxPainter.cpp
index 3b15cff3..06016f14 100644
--- a/third_party/WebKit/Source/core/paint/BoxPainter.cpp
+++ b/third_party/WebKit/Source/core/paint/BoxPainter.cpp
@@ -77,9 +77,7 @@
     // The background painting code assumes that the borders are part of the
     // paintRect so we expand the paintRect by the border size when painting the
     // background into the scrolling contents layer.
-    paint_rect.ExpandEdges(layout_box_.BorderTop(), layout_box_.BorderRight(),
-                           layout_box_.BorderBottom(),
-                           layout_box_.BorderLeft());
+    paint_rect.Expand(layout_box_.BorderBoxOutsets());
   } else {
     paint_rect = layout_box_.BorderBoxRect();
   }
diff --git a/third_party/WebKit/Source/core/paint/PaintInvalidationTest.cpp b/third_party/WebKit/Source/core/paint/PaintInvalidationTest.cpp
index d1e2ead7c9..f3654483 100644
--- a/third_party/WebKit/Source/core/paint/PaintInvalidationTest.cpp
+++ b/third_party/WebKit/Source/core/paint/PaintInvalidationTest.cpp
@@ -192,7 +192,7 @@
   GetDocument().domWindow()->scrollTo(0, 4000);
   GetDocument().View()->UpdateAllLifecyclePhases();
   const auto& raster_invalidations =
-      GetRasterInvalidationTracking()->tracked_raster_invalidations;
+      GetRasterInvalidationTracking()->invalidations;
   ASSERT_EQ(1u, raster_invalidations.size());
   EXPECT_EQ(kPaintInvalidationNone, target->FullPaintInvalidationReason());
   EXPECT_EQ(IntRect(0, 4000, 100, 100), raster_invalidations[0].rect);
diff --git a/third_party/WebKit/Source/core/paint/PaintInvalidator.h b/third_party/WebKit/Source/core/paint/PaintInvalidator.h
index 8ad1ab1a..c3e1cc7 100644
--- a/third_party/WebKit/Source/core/paint/PaintInvalidator.h
+++ b/third_party/WebKit/Source/core/paint/PaintInvalidator.h
@@ -13,6 +13,9 @@
 namespace blink {
 
 struct PaintInvalidatorContext {
+  USING_FAST_MALLOC(PaintInvalidatorContext);
+
+ public:
   PaintInvalidatorContext() : parent_context(nullptr) {}
 
   PaintInvalidatorContext(const PaintInvalidatorContext& parent_context)
diff --git a/third_party/WebKit/Source/core/paint/PrePaintTreeWalk.cpp b/third_party/WebKit/Source/core/paint/PrePaintTreeWalk.cpp
index d363bd8b..346651b 100644
--- a/third_party/WebKit/Source/core/paint/PrePaintTreeWalk.cpp
+++ b/third_party/WebKit/Source/core/paint/PrePaintTreeWalk.cpp
@@ -19,6 +19,7 @@
   PrePaintTreeWalkContext()
       : tree_builder_context(
             WTF::WrapUnique(new PaintPropertyTreeBuilderContext)),
+        paint_invalidator_context(WTF::WrapUnique(new PaintInvalidatorContext)),
         ancestor_overflow_paint_layer(nullptr),
         ancestor_transformed_or_root_paint_layer(nullptr) {}
 
@@ -29,7 +30,8 @@
                                 ? new PaintPropertyTreeBuilderContext(
                                       *parent_context.tree_builder_context)
                                 : nullptr)),
-        paint_invalidator_context(parent_context.paint_invalidator_context),
+        paint_invalidator_context(WTF::WrapUnique(new PaintInvalidatorContext(
+            *parent_context.paint_invalidator_context))),
         ancestor_overflow_paint_layer(
             parent_context.ancestor_overflow_paint_layer),
         ancestor_transformed_or_root_paint_layer(
@@ -46,7 +48,7 @@
   // See: https://crbug.com/698653.
   std::unique_ptr<PaintPropertyTreeBuilderContext> tree_builder_context;
 
-  PaintInvalidatorContext paint_invalidator_context;
+  std::unique_ptr<PaintInvalidatorContext> paint_invalidator_context;
 
   // The ancestor in the PaintLayer tree which has overflow clip, or
   // is the root layer. Note that it is tree ancestor, not containing
@@ -93,7 +95,7 @@
   }
   paint_invalidator_.InvalidatePaint(frame_view,
                                      context.tree_builder_context.get(),
-                                     context.paint_invalidator_context);
+                                     *context.paint_invalidator_context);
 
   if (LayoutView* view = frame_view.GetLayoutView()) {
     Walk(*view, context);
@@ -155,7 +157,7 @@
   PaintLayer& paint_layer = *ToLayoutBoxModelObject(object).Layer();
   if (object.StyleRef().HasTransform() ||
       &object ==
-          context.paint_invalidator_context.paint_invalidation_container) {
+          context.paint_invalidator_context->paint_invalidation_container) {
     context.ancestor_transformed_or_root_paint_layer = &paint_layer;
   }
 
@@ -174,7 +176,7 @@
     if (InvalidatePaintLayerOptimizationsForFragment(
             object, context.ancestor_transformed_or_root_paint_layer, fragment,
             *fragment_data)) {
-      context.paint_invalidator_context.forced_subtree_invalidation_flags |=
+      context.paint_invalidator_context->forced_subtree_invalidation_flags |=
           PaintInvalidatorContext::kForcedSubtreeVisualRectUpdate;
     }
     fragment_data = fragment_data->NextFragment();
@@ -281,7 +283,8 @@
           parent_context.tree_builder_context->force_subtree_update) ||
          // If the object needs visual rect update, we should update tree
          // builder context which is needed by visual rect update.
-         parent_context.paint_invalidator_context.NeedsVisualRectUpdate(object);
+         parent_context.paint_invalidator_context->NeedsVisualRectUpdate(
+             object);
 }
 
 void PrePaintTreeWalk::ClearPreviousClipRectsForTesting(
@@ -312,7 +315,7 @@
   }
 
   paint_invalidator_.InvalidatePaint(object, context.tree_builder_context.get(),
-                                     context.paint_invalidator_context);
+                                     *context.paint_invalidator_context);
 
   if (context.tree_builder_context) {
     property_tree_builder_.UpdatePropertiesForChildren(
diff --git a/third_party/WebKit/Source/core/style/ComputedStyle.cpp b/third_party/WebKit/Source/core/style/ComputedStyle.cpp
index fe7f67576..e6f1d15b 100644
--- a/third_party/WebKit/Source/core/style/ComputedStyle.cpp
+++ b/third_party/WebKit/Source/core/style/ComputedStyle.cpp
@@ -72,11 +72,11 @@
 // re-create the same structure for an accurate size comparison.
 struct SameSizeAsComputedStyle : public RefCounted<SameSizeAsComputedStyle> {
   struct ComputedStyleBase {
-    void* data_refs[3];
+    void* data_refs[4];
     unsigned bitfields_[4];
   } base_;
 
-  void* data_refs[4];
+  void* data_refs[3];
   void* own_ptrs[1];
   void* data_ref_svg_style;
 };
@@ -115,7 +115,6 @@
 
 ALWAYS_INLINE ComputedStyle::ComputedStyle()
     : ComputedStyleBase(), RefCounted<ComputedStyle>() {
-  box_data_.Init();
   rare_non_inherited_data_.Init();
   rare_non_inherited_data_.Access()->deprecated_flexible_box_.Init();
   rare_non_inherited_data_.Access()->flexible_box_.Init();
@@ -135,7 +134,6 @@
 ALWAYS_INLINE ComputedStyle::ComputedStyle(const ComputedStyle& o)
     : ComputedStyleBase(o),
       RefCounted<ComputedStyle>(),
-      box_data_(o.box_data_),
       rare_non_inherited_data_(o.rare_non_inherited_data_),
       rare_inherited_data_(o.rare_inherited_data_),
       inherited_data_(o.inherited_data_),
@@ -328,7 +326,6 @@
 
 void ComputedStyle::CopyNonInheritedFromCached(const ComputedStyle& other) {
   ComputedStyleBase::CopyNonInheritedFromCached(other);
-  box_data_ = other.box_data_;
   rare_non_inherited_data_ = other.rare_non_inherited_data_;
 
   // The flags are copied one-by-one because they contain
@@ -468,7 +465,6 @@
 bool ComputedStyle::NonInheritedEqual(const ComputedStyle& other) const {
   // compare everything except the pseudoStyle pointer
   return ComputedStyleBase::NonInheritedEqual(other) &&
-         box_data_ == other.box_data_ &&
          rare_non_inherited_data_ == other.rare_non_inherited_data_ &&
          svg_style_->NonInheritedEqual(*other.svg_style_);
 }
diff --git a/third_party/WebKit/Source/core/style/ComputedStyle.h b/third_party/WebKit/Source/core/style/ComputedStyle.h
index 77a3e50..e81d8705 100644
--- a/third_party/WebKit/Source/core/style/ComputedStyle.h
+++ b/third_party/WebKit/Source/core/style/ComputedStyle.h
@@ -180,61 +180,8 @@
   friend class StyleResolverState;
   friend class StyleResolver;
 
- private:
-  class StyleBoxData : public RefCountedCopyable<StyleBoxData> {
-   public:
-    static PassRefPtr<StyleBoxData> Create() {
-      return AdoptRef(new StyleBoxData);
-    }
-    PassRefPtr<StyleBoxData> Copy() const {
-      return AdoptRef(new StyleBoxData(*this));
-    }
-
-    bool operator==(const StyleBoxData& other) const {
-      return width_ == other.width_ && height_ == other.height_ &&
-             min_width_ == other.min_width_ && max_width_ == other.max_width_ &&
-             min_height_ == other.min_height_ &&
-             max_height_ == other.max_height_ &&
-             vertical_align_length_ == other.vertical_align_length_ &&
-             z_index_ == other.z_index_ &&
-             has_auto_z_index_ == other.has_auto_z_index_ &&
-             box_sizing_ == other.box_sizing_ &&
-             box_decoration_break_ == other.box_decoration_break_;
-    }
-    bool operator!=(const StyleBoxData& o) const { return !(*this == o); }
-
-    Length width_;
-    Length height_;
-    Length min_width_;
-    Length max_width_;
-    Length min_height_;
-    Length max_height_;
-    Length vertical_align_length_;
-    int z_index_;
-    unsigned has_auto_z_index_ : 1;
-    unsigned box_sizing_ : 1;            // EBoxSizing
-    unsigned box_decoration_break_ : 1;  // EBoxDecorationBreak
-
-   private:
-    StyleBoxData()
-        : width_(Length()),
-          height_(Length()),
-          min_width_(Length()),
-          max_width_(Length(kMaxSizeNone)),
-          min_height_(Length()),
-          max_height_(Length(kMaxSizeNone)),
-          z_index_(0),
-          has_auto_z_index_(static_cast<unsigned>(true)),
-          box_sizing_(static_cast<unsigned>(EBoxSizing::kContentBox)),
-          box_decoration_break_(
-              static_cast<unsigned>(EBoxDecorationBreak::kSlice)) {}
-
-    StyleBoxData(const StyleBoxData&) = default;
-  };
-
  protected:
   // non-inherited attributes
-  DataRef<StyleBoxData> box_data_;
   DataRef<StyleRareNonInheritedData> rare_non_inherited_data_;
 
   // inherited attributes
diff --git a/third_party/WebKit/Source/devtools/BUILD.gn b/third_party/WebKit/Source/devtools/BUILD.gn
index 77d11aa..322b6ce1 100644
--- a/third_party/WebKit/Source/devtools/BUILD.gn
+++ b/third_party/WebKit/Source/devtools/BUILD.gn
@@ -137,6 +137,8 @@
   "front_end/components/Linkifier.js",
   "front_end/components/module.json",
   "front_end/components/Reload.js",
+  "front_end/console/consoleContextSelector.css",
+  "front_end/console/consoleContextSelectorButton.css",
   "front_end/console/ConsoleContextSelector.js",
   "front_end/console/ConsolePanel.js",
   "front_end/console/ConsolePrompt.js",
@@ -657,6 +659,7 @@
   "front_end/ui/Icon.js",
   "front_end/ui/infobar.css",
   "front_end/ui/Infobar.js",
+  "front_end/ui/inlineButton.css",
   "front_end/ui/InplaceEditor.js",
   "front_end/ui/inspectorCommon.css",
   "front_end/ui/inspectorStyle.css",
diff --git a/third_party/WebKit/Source/devtools/front_end/Tests.js b/third_party/WebKit/Source/devtools/front_end/Tests.js
index b0c51b9..1177154 100644
--- a/third_party/WebKit/Source/devtools/front_end/Tests.js
+++ b/third_party/WebKit/Source/devtools/front_end/Tests.js
@@ -847,10 +847,10 @@
 
     function onExecutionContexts() {
       var consoleView = Console.ConsoleView.instance();
-      var options = consoleView._consoleContextSelector._selectElement.options;
+      var items = consoleView._consoleContextSelector._list._items;
       var values = [];
-      for (var i = 0; i < options.length; ++i)
-        values.push(options[i].value.trim());
+      for (var i = 0; i < items.length; ++i)
+        values.push(consoleView._consoleContextSelector._titleFor(items[i]));
       test.assertEquals('top', values[0]);
       test.assertEquals('Simple content script', values[1]);
       test.releaseControl();
diff --git a/third_party/WebKit/Source/devtools/front_end/console/ConsoleContextSelector.js b/third_party/WebKit/Source/devtools/front_end/console/ConsoleContextSelector.js
index 127d7cee..d1ca0b8 100644
--- a/third_party/WebKit/Source/devtools/front_end/console/ConsoleContextSelector.js
+++ b/third_party/WebKit/Source/devtools/front_end/console/ConsoleContextSelector.js
@@ -3,18 +3,58 @@
 // found in the LICENSE file.
 /**
  * @implements {SDK.SDKModelObserver<!SDK.RuntimeModel>}
- * @unrestricted
+ * @implements {UI.ListDelegate<!SDK.ExecutionContext>}
  */
 Console.ConsoleContextSelector = class {
-  /**
-   * @param {!Element} selectElement
-   */
-  constructor(selectElement) {
-    this._selectElement = selectElement;
-    /**
-     * @type {!Map.<!SDK.ExecutionContext, !Element>}
-     */
-    this._optionByExecutionContext = new Map();
+  constructor() {
+    this._toolbarItem = new UI.ToolbarItem(createElementWithClass('button', 'console-context'));
+    var shadowRoot =
+        UI.createShadowRootWithCoreStyles(this._toolbarItem.element, 'console/consoleContextSelectorButton.css');
+    this._titleElement = shadowRoot.createChild('span', 'title');
+    this._productRegistry = null;
+
+    ProductRegistry.instance().then(registry => {
+      this._productRegistry = registry;
+      this._list.refreshAllItems();
+    });
+    this._toolbarItem.element.classList.add('toolbar-has-dropdown');
+    this._toolbarItem.element.tabIndex = 0;
+    this._glassPane = new UI.GlassPane();
+    this._glassPane.setMarginBehavior(UI.GlassPane.MarginBehavior.NoMargin);
+    this._glassPane.setAnchorBehavior(UI.GlassPane.AnchorBehavior.PreferBottom);
+    this._glassPane.setOutsideClickCallback(this._hide.bind(this));
+    this._glassPane.setPointerEventsBehavior(UI.GlassPane.PointerEventsBehavior.BlockedByGlassPane);
+    this._list = new UI.ListControl(this, UI.ListMode.EqualHeightItems);
+    this._list.element.classList.add('context-list');
+    this._list.element.tabIndex = -1;
+    this._rowHeight = 34;
+    UI.createShadowRootWithCoreStyles(this._glassPane.contentElement, 'console/consoleContextSelector.css')
+        .appendChild(this._list.element);
+
+    this._listWasShowing200msAgo = false;
+    this._toolbarItem.element.addEventListener('mousedown', event => {
+      if (this._listWasShowing200msAgo)
+        this._hide(event);
+      else
+        this._show(event);
+    }, false);
+    this._toolbarItem.element.addEventListener('keydown', this._onKeyDown.bind(this), false);
+    this._toolbarItem.element.addEventListener('focusout', this._hide.bind(this), false);
+    this._list.element.addEventListener('mousedown', event => {
+      event.consume(true);
+    }, false);
+    this._list.element.addEventListener('mouseup', event => {
+      if (event.target === this._list.element)
+        return;
+
+      if (!this._listWasShowing200msAgo)
+        return;
+      this._updateSelectedContext();
+      this._hide(event);
+    }, false);
+
+    var dropdownArrowIcon = UI.Icon.create('smallicon-triangle-down');
+    shadowRoot.appendChild(dropdownArrowIcon);
 
     SDK.targetManager.addModelListener(
         SDK.RuntimeModel, SDK.RuntimeModel.Events.ExecutionContextCreated, this._onExecutionContextCreated, this);
@@ -22,8 +62,9 @@
         SDK.RuntimeModel, SDK.RuntimeModel.Events.ExecutionContextChanged, this._onExecutionContextChanged, this);
     SDK.targetManager.addModelListener(
         SDK.RuntimeModel, SDK.RuntimeModel.Events.ExecutionContextDestroyed, this._onExecutionContextDestroyed, this);
+    SDK.targetManager.addModelListener(
+        SDK.ResourceTreeModel, SDK.ResourceTreeModel.Events.FrameNavigated, this._frameNavigated, this);
 
-    this._selectElement.addEventListener('change', this._executionContextChanged.bind(this), false);
     UI.context.addFlavorChangeListener(SDK.ExecutionContext, this._executionContextChangedExternally, this);
     UI.context.addFlavorChangeListener(SDK.DebuggerModel.CallFrame, this._callFrameSelectedInUI, this);
     SDK.targetManager.observeModels(SDK.RuntimeModel, this);
@@ -32,27 +73,182 @@
   }
 
   /**
+   * @return {!UI.ToolbarItem}
+   */
+  toolbarItem() {
+    return this._toolbarItem;
+  }
+
+  /**
+   * @param {!Event} event
+   */
+  _show(event) {
+    if (this._glassPane.isShowing())
+      return;
+    this._glassPane.setContentAnchorBox(this._toolbarItem.element.boxInWindow());
+    this._glassPane.show(/** @type {!Document} **/ (this._toolbarItem.element.ownerDocument));
+    this._updateGlasspaneSize();
+    var selectedItem = this._list.selectedItem();
+    if (selectedItem)
+      this._list.scrollItemIntoView(selectedItem, true);
+    this._toolbarItem.element.focus();
+    event.consume(true);
+    setTimeout(() => this._listWasShowing200msAgo = true, 200);
+  }
+
+  _updateGlasspaneSize() {
+    var maxHeight = this._rowHeight * (Math.min(this._list.length(), 9));
+    this._glassPane.setMaxContentSize(new UI.Size(315, maxHeight));
+    this._list.viewportResized();
+  }
+
+  /**
+   * @param {!Event} event
+   */
+  _hide(event) {
+    setTimeout(() => this._listWasShowing200msAgo = false, 200);
+    this._glassPane.hide();
+    SDK.OverlayModel.hideDOMNodeHighlight();
+    var selectedContext = UI.context.flavor(SDK.ExecutionContext);
+    if (selectedContext)
+      this._list.selectItem(selectedContext);
+    event.consume(true);
+  }
+
+  /**
+   * @param {!Event} event
+   */
+  _onKeyDown(event) {
+    var handled = false;
+    switch (event.key) {
+      case 'ArrowUp':
+        handled = this._list.selectPreviousItem(false, false);
+        break;
+      case 'ArrowDown':
+        handled = this._list.selectNextItem(false, false);
+        break;
+      case 'ArrowRight':
+        var currentExecutionContext = this._list.selectedItem();
+        if (!currentExecutionContext)
+          break;
+        var nextExecutionContext = this._list.itemAtIndex(this._list.selectedIndex() + 1);
+        if (nextExecutionContext && this._depthFor(currentExecutionContext) < this._depthFor(nextExecutionContext))
+          handled = this._list.selectNextItem(false, false);
+        break;
+      case 'ArrowLeft':
+        var currentExecutionContext = this._list.selectedItem();
+        if (!currentExecutionContext)
+          break;
+        var depth = this._depthFor(currentExecutionContext);
+        for (var i = this._list.selectedIndex() - 1; i >= 0; i--) {
+          if (this._depthFor(this._list.itemAtIndex(i)) < depth) {
+            handled = true;
+            this._list.selectItem(this._list.itemAtIndex(i), false);
+            break;
+          }
+        }
+        break;
+      case 'PageUp':
+        handled = this._list.selectItemPreviousPage(false);
+        break;
+      case 'PageDown':
+        handled = this._list.selectItemNextPage(false);
+        break;
+      case 'Home':
+        for (var i = 0; i < this._list.length(); i++) {
+          if (this.isItemSelectable(this._list.itemAtIndex(i))) {
+            this._list.selectItem(this._list.itemAtIndex(i));
+            handled = true;
+            break;
+          }
+        }
+        break;
+      case 'End':
+        for (var i = this._list.length() - 1; i >= 0; i--) {
+          if (this.isItemSelectable(this._list.itemAtIndex(i))) {
+            this._list.selectItem(this._list.itemAtIndex(i));
+            handled = true;
+            break;
+          }
+        }
+        break;
+      case 'Escape':
+        this._hide(event);
+        break;
+      case 'Tab':
+        if (!this._glassPane.isShowing())
+          break;
+        this._updateSelectedContext();
+        this._hide(event);
+        break;
+      case 'Enter':
+        if (!this._glassPane.isShowing()) {
+          this._show(event);
+          break;
+        }
+        this._updateSelectedContext();
+        this._hide(event);
+        break;
+      case ' ':
+        this._show(event);
+        break;
+      default:
+        if (event.key.length === 1) {
+          var selectedIndex = this._list.selectedIndex();
+          var letter = event.key.toUpperCase();
+          for (var i = 0; i < this._list.length(); i++) {
+            var context = this._list.itemAtIndex((selectedIndex + i + 1) % this._list.length());
+            if (this._titleFor(context).toUpperCase().startsWith(letter)) {
+              this._list.selectItem(context);
+              break;
+            }
+          }
+          handled = true;
+        }
+        break;
+    }
+
+    if (handled) {
+      event.consume(true);
+      this._updateSelectedContext();
+    }
+  }
+
+  /**
    * @param {!SDK.ExecutionContext} executionContext
    * @return {string}
    */
   _titleFor(executionContext) {
     var target = executionContext.target();
-    var depth = 0;
     var label = executionContext.label() ? target.decorateLabel(executionContext.label()) : '';
+    if (executionContext.frameId) {
+      var resourceTreeModel = target.model(SDK.ResourceTreeModel);
+      var frame = resourceTreeModel && resourceTreeModel.frameForId(executionContext.frameId);
+      if (frame)
+        label = label || frame.displayName();
+    }
+    label = label || executionContext.origin;
+
+    return label;
+  }
+
+  /**
+   * @param {!SDK.ExecutionContext} executionContext
+   * @return {number}
+   */
+  _depthFor(executionContext) {
+    var target = executionContext.target();
+    var depth = 0;
     if (!executionContext.isDefault)
       depth++;
     if (executionContext.frameId) {
       var resourceTreeModel = target.model(SDK.ResourceTreeModel);
       var frame = resourceTreeModel && resourceTreeModel.frameForId(executionContext.frameId);
-      if (frame) {
-        label = label || frame.displayName();
-        while (frame.parentFrame) {
-          depth++;
-          frame = frame.parentFrame;
-        }
+      while (frame && frame.parentFrame) {
+        depth++;
+        frame = frame.parentFrame;
       }
     }
-    label = label || executionContext.origin;
     var targetDepth = 0;
     while (target.parentTarget()) {
       if (target.parentTarget().hasJSCapability()) {
@@ -64,11 +260,8 @@
       }
       target = target.parentTarget();
     }
-
     depth += targetDepth;
-    var prefix = new Array(4 * depth + 1).join('\u00a0');
-    var maxLength = 50;
-    return (prefix + label).trimMiddle(maxLength);
+    return depth;
   }
 
   /**
@@ -80,25 +273,11 @@
     if (!executionContext.target().hasJSCapability())
       return;
 
-    var newOption = createElement('option');
-    newOption.__executionContext = executionContext;
-    newOption.text = this._titleFor(executionContext);
-    this._optionByExecutionContext.set(executionContext, newOption);
-    var options = this._selectElement.options;
-    var contexts = Array.prototype.map.call(options, mapping);
-    var index = contexts.lowerBound(executionContext, executionContext.runtimeModel.executionContextComparator());
-    this._selectElement.insertBefore(newOption, options[index]);
+    this._list.insertItemWithComparator(executionContext, executionContext.runtimeModel.executionContextComparator());
 
-    if (executionContext === UI.context.flavor(SDK.ExecutionContext))
-      this._select(newOption);
-    this._updateOptionDisabledState(newOption);
-
-    /**
-     * @param {!Element} option
-     * @return {!SDK.ExecutionContext}
-     */
-    function mapping(option) {
-      return option.__executionContext;
+    if (executionContext === UI.context.flavor(SDK.ExecutionContext)) {
+      this._list.selectItem(executionContext);
+      this._updateSelectedContext();
     }
   }
 
@@ -109,6 +288,7 @@
     var executionContext = /** @type {!SDK.ExecutionContext} */ (event.data);
     this._executionContextCreated(executionContext);
     this._updateSelectionWarning();
+    this._updateGlasspaneSize();
   }
 
   /**
@@ -116,9 +296,10 @@
    */
   _onExecutionContextChanged(event) {
     var executionContext = /** @type {!SDK.ExecutionContext} */ (event.data);
-    var option = this._optionByExecutionContext.get(executionContext);
-    if (option)
-      option.text = this._titleFor(executionContext);
+    if (this._list.indexOfItem(executionContext) === -1)
+      return;
+    this._executionContextDestroyed(executionContext);
+    this._executionContextCreated(executionContext);
     this._updateSelectionWarning();
   }
 
@@ -126,8 +307,10 @@
    * @param {!SDK.ExecutionContext} executionContext
    */
   _executionContextDestroyed(executionContext) {
-    var option = this._optionByExecutionContext.remove(executionContext);
-    option.remove();
+    if (this._list.indexOfItem(executionContext) === -1)
+      return;
+    this._list.removeItem(executionContext);
+    this._updateGlasspaneSize();
   }
 
   /**
@@ -144,26 +327,15 @@
    */
   _executionContextChangedExternally(event) {
     var executionContext = /** @type {?SDK.ExecutionContext} */ (event.data);
-    if (!executionContext)
+    if (!executionContext || this._list.indexOfItem(executionContext) === -1)
       return;
-
-    var options = this._selectElement.options;
-    for (var i = 0; i < options.length; ++i) {
-      if (options[i].__executionContext === executionContext)
-        this._select(options[i]);
-    }
-  }
-
-  _executionContextChanged() {
-    var option = this._selectedOption();
-    var newContext = option ? option.__executionContext : null;
-    UI.context.setFlavor(SDK.ExecutionContext, newContext);
-    this._updateSelectionWarning();
+    this._list.selectItem(executionContext);
+    this._updateSelectedContext();
   }
 
   _updateSelectionWarning() {
     var executionContext = UI.context.flavor(SDK.ExecutionContext);
-    this._selectElement.parentElement.classList.toggle(
+    this._toolbarItem.element.classList.toggle(
         'warning', !this._isTopContext(executionContext) && this._hasTopContext());
   }
 
@@ -185,9 +357,8 @@
    * @return {boolean}
    */
   _hasTopContext() {
-    var options = this._selectElement.options;
-    for (var i = 0; i < options.length; i++) {
-      if (this._isTopContext(options[i].__executionContext))
+    for (var i = 0; i < this._list.length(); i++) {
+      if (this._isTopContext(this._list.itemAtIndex(i)))
         return true;
     }
     return false;
@@ -206,50 +377,117 @@
    * @param {!SDK.RuntimeModel} runtimeModel
    */
   modelRemoved(runtimeModel) {
-    var executionContexts = this._optionByExecutionContext.keysArray();
-    for (var i = 0; i < executionContexts.length; ++i) {
-      if (executionContexts[i].runtimeModel === runtimeModel)
-        this._executionContextDestroyed(executionContexts[i]);
+    for (var i = 0; i < this._list.length(); i++) {
+      if (this._list.itemAtIndex(i).runtimeModel === runtimeModel)
+        this._executionContextDestroyed(this._list.itemAtIndex(i));
     }
   }
 
   /**
-   * @param {!Element} option
+   * @override
+   * @param {!SDK.ExecutionContext} item
+   * @return {!Element}
    */
-  _select(option) {
-    this._selectElement.selectedIndex = Array.prototype.indexOf.call(/** @type {?} */ (this._selectElement), option);
-    this._updateSelectionWarning();
+  createElementForItem(item) {
+    var element = createElementWithClass('div', 'context');
+    element.style.paddingLeft = (8 + this._depthFor(item) * 15) + 'px';
+    element.createChild('div', 'title').textContent = this._titleFor(item).trimEnd(100);
+    element.createChild('div', 'subtitle').textContent = this._subtitleFor(item);
+    element.addEventListener('mousemove', e => {
+      if ((e.movementX || e.movementY) && this.isItemSelectable(item))
+        this._list.selectItem(item, false, /* Don't scroll */ true);
+    });
+    element.classList.toggle('disabled', !this.isItemSelectable(item));
+    return element;
   }
 
   /**
-   * @return {?Element}
+   * @param {!SDK.ExecutionContext} executionContext
+   * @return {string}
    */
-  _selectedOption() {
-    if (this._selectElement.selectedIndex >= 0)
-      return this._selectElement[this._selectElement.selectedIndex];
-    return null;
-  }
-
-  /**
-   * @param {!Common.Event} event
-   */
-  _callFrameSelectedInModel(event) {
-    var debuggerModel = /** @type {!SDK.DebuggerModel} */ (event.data);
-    var options = this._selectElement.options;
-    for (var i = 0; i < options.length; i++) {
-      if (options[i].__executionContext.debuggerModel === debuggerModel)
-        this._updateOptionDisabledState(options[i]);
+  _subtitleFor(executionContext) {
+    var target = executionContext.target();
+    if (executionContext.frameId) {
+      var resourceTreeModel = target.model(SDK.ResourceTreeModel);
+      var frame = resourceTreeModel && resourceTreeModel.frameForId(executionContext.frameId);
     }
+    if (executionContext.origin.startsWith('chrome-extension://'))
+      return Common.UIString('Extension');
+    if (!frame || !frame.parentFrame || frame.parentFrame.securityOrigin !== executionContext.origin) {
+      var url = executionContext.origin.asParsedURL();
+      if (url) {
+        if (this._productRegistry) {
+          var product = this._productRegistry.nameForUrl(url);
+          if (product)
+            return product;
+        }
+        return url.domain();
+      }
+    }
+
+    if (frame) {
+      var callFrame = frame.findCreationCallFrame(callFrame => !!callFrame.url);
+      if (callFrame) {
+        var url = new Common.ParsedURL(callFrame.url);
+        if (this._productRegistry) {
+          var product = this._productRegistry.nameForUrl(url);
+          if (product)
+            return product;
+        }
+        return url.domain();
+      }
+    }
+    return '';
   }
 
   /**
-   * @param {!Element} option
+   * @override
+   * @param {!SDK.ExecutionContext} item
+   * @return {number}
    */
-  _updateOptionDisabledState(option) {
-    var executionContext = option.__executionContext;
-    var callFrame = executionContext.debuggerModel.selectedCallFrame();
+  heightForItem(item) {
+    return 0;
+  }
+
+  /**
+   * @override
+   * @param {!SDK.ExecutionContext} item
+   * @return {boolean}
+   */
+  isItemSelectable(item) {
+    var callFrame = item.debuggerModel.selectedCallFrame();
     var callFrameContext = callFrame && callFrame.script.executionContext();
-    option.disabled = callFrameContext && executionContext !== callFrameContext;
+    return !callFrameContext || item === callFrameContext;
+  }
+
+  /**
+   * @override
+   * @param {?SDK.ExecutionContext} from
+   * @param {?SDK.ExecutionContext} to
+   * @param {?Element} fromElement
+   * @param {?Element} toElement
+   */
+  selectedItemChanged(from, to, fromElement, toElement) {
+    if (fromElement)
+      fromElement.classList.remove('selected');
+    if (toElement)
+      toElement.classList.add('selected');
+    SDK.OverlayModel.hideDOMNodeHighlight();
+    if (to && to.frameId) {
+      var resourceTreeModel = to.target().model(SDK.ResourceTreeModel);
+      if (resourceTreeModel)
+        resourceTreeModel.domModel().overlayModel().highlightFrame(to.frameId);
+    }
+  }
+
+  _updateSelectedContext() {
+    var context = this._list.selectedItem();
+    if (context)
+      this._titleElement.textContent = this._titleFor(context);
+    else
+      this._titleElement.textContent = '';
+    UI.context.setFlavor(SDK.ExecutionContext, context);
+    this._updateSelectionWarning();
   }
 
   _callFrameSelectedInUI() {
@@ -258,4 +496,26 @@
     if (callFrameContext)
       UI.context.setFlavor(SDK.ExecutionContext, callFrameContext);
   }
+
+  /**
+   * @param {!Common.Event} event
+   */
+  _callFrameSelectedInModel(event) {
+    var debuggerModel = /** @type {!SDK.DebuggerModel} */ (event.data);
+    for (var i = 0; i < this._list.length(); i++) {
+      if (this._list.itemAtIndex(i).debuggerModel === debuggerModel)
+        this._list.refreshItemsInRange(i, i + 1);
+    }
+  }
+
+  /**
+   * @param {!Common.Event} event
+   */
+  _frameNavigated(event) {
+    var frameId = event.data.id;
+    for (var i = 0; i < this._list.length(); i++) {
+      if (frameId === this._list.itemAtIndex(i).frameId)
+        this._list.refreshItemsInRange(i, i + 1);
+    }
+  }
 };
diff --git a/third_party/WebKit/Source/devtools/front_end/console/ConsoleView.js b/third_party/WebKit/Source/devtools/front_end/console/ConsoleView.js
index 4b64e34..73c6dd7 100644
--- a/third_party/WebKit/Source/devtools/front_end/console/ConsoleView.js
+++ b/third_party/WebKit/Source/devtools/front_end/console/ConsoleView.js
@@ -55,9 +55,7 @@
     this._regexMatchRanges = [];
     this._filter = new Console.ConsoleViewFilter(this._updateMessageList.bind(this));
 
-    this._executionContextComboBox = new UI.ToolbarComboBox(null, 'console-context');
-    this._executionContextComboBox.setMaxWidth(80);
-    this._consoleContextSelector = new Console.ConsoleContextSelector(this._executionContextComboBox.selectElement());
+    this._consoleContextSelector = new Console.ConsoleContextSelector();
 
     this._filterStatusText = new UI.ToolbarText();
     this._filterStatusText.element.classList.add('dimmed');
@@ -70,7 +68,7 @@
     toolbar.appendToolbarItem(UI.Toolbar.createActionButton(
         /** @type {!UI.Action }*/ (UI.actionRegistry.action('console.clear'))));
     toolbar.appendSeparator();
-    toolbar.appendToolbarItem(this._executionContextComboBox);
+    toolbar.appendToolbarItem(this._consoleContextSelector.toolbarItem());
     toolbar.appendSeparator();
     toolbar.appendToolbarItem(this._filter._textFilterUI);
     toolbar.appendToolbarItem(this._filter._levelComboBox);
diff --git a/third_party/WebKit/Source/devtools/front_end/console/consoleContextSelector.css b/third_party/WebKit/Source/devtools/front_end/console/consoleContextSelector.css
new file mode 100644
index 0000000..845c9ae
--- /dev/null
+++ b/third_party/WebKit/Source/devtools/front_end/console/consoleContextSelector.css
@@ -0,0 +1,50 @@
+/*
+ * 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.
+ */
+.context {
+    padding: 2px 1px 2px 2px;
+    white-space: nowrap;
+    display: flex;
+    flex-direction: column;
+    height: 34px;
+    justify-content: center;
+}
+
+.context.disabled {
+    opacity: 0.5;
+}
+
+.title {
+    overflow: hidden;
+    text-overflow: ellipsis;
+    flex-grow: 0;
+}
+
+.subtitle {
+    color: #999;
+    margin-right: 3px;
+    overflow: hidden;
+    text-overflow: ellipsis;
+    flex-grow: 0;
+}
+
+.context-list {
+    background-color: white;
+    box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.05),
+                0 2px 4px rgba(0, 0, 0, 0.2),
+                0 2px 6px rgba(0, 0, 0, 0.1);
+    overflow-x: hidden;
+    overflow-y: auto;
+    width: 100%;
+}
+
+.context.selected {
+    color: white;
+    background-color: rgb(56, 121, 217);
+}
+
+.context.selected .subtitle {
+    color: white;
+}
diff --git a/third_party/WebKit/Source/devtools/front_end/console/consoleContextSelectorButton.css b/third_party/WebKit/Source/devtools/front_end/console/consoleContextSelectorButton.css
new file mode 100644
index 0000000..578b2b7
--- /dev/null
+++ b/third_party/WebKit/Source/devtools/front_end/console/consoleContextSelectorButton.css
@@ -0,0 +1,35 @@
+/*
+ * 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.
+ */
+:host {
+    height: 26px;
+    text-align: left;
+}
+
+:host([disabled]) {
+    opacity: .5;
+}
+
+:host .title {
+    padding-right: 5px;
+    width: 120px;
+    overflow: hidden;
+    text-overflow: ellipsis;
+}
+
+:host([data-keyboard-focus="true"]:focus)::before {
+    content: "";
+    position: absolute;
+    top: 2px;
+    left: 2px;
+    right: 2px;
+    bottom: 2px;
+    border-radius: 2px;
+    background: rgba(0, 0, 0, 0.08);
+}
+
+:host(.warning) {
+    background: #ffd7d7 !important;
+}
diff --git a/third_party/WebKit/Source/devtools/front_end/console/module.json b/third_party/WebKit/Source/devtools/front_end/console/module.json
index c94885e..f0707df 100644
--- a/third_party/WebKit/Source/devtools/front_end/console/module.json
+++ b/third_party/WebKit/Source/devtools/front_end/console/module.json
@@ -126,7 +126,8 @@
         "components",
         "data_grid",
         "object_ui",
-        "console_model"
+        "console_model",
+        "product_registry"
     ],
     "scripts": [
         "ConsoleContextSelector.js",
@@ -137,6 +138,8 @@
         "ConsolePanel.js"
     ],
     "resources": [
+        "consoleContextSelector.css",
+        "consoleContextSelectorButton.css",
         "consoleView.css"
     ]
 }
diff --git a/third_party/WebKit/Source/devtools/front_end/coverage/CoverageListView.js b/third_party/WebKit/Source/devtools/front_end/coverage/CoverageListView.js
index 48d48725..16d890e2 100644
--- a/third_party/WebKit/Source/devtools/front_end/coverage/CoverageListView.js
+++ b/third_party/WebKit/Source/devtools/front_end/coverage/CoverageListView.js
@@ -139,7 +139,7 @@
       var nodeA = /** @type {!Coverage.CoverageListView.GridNode} */ (a);
       var nodeB = /** @type {!Coverage.CoverageListView.GridNode} */ (b);
 
-      return nodeA._displayURL.localeCompare(nodeB._displayURL);
+      return nodeA._url.localeCompare(nodeB._url);
     }
 
     /**
@@ -193,7 +193,6 @@
     /** @type {number|undefined} */
     this._lastUsedSize;
     this._url = coverageInfo.url();
-    this._displayURL = new Common.ParsedURL(this._url).displayName;
     this._maxSize = maxSize;
   }
 
diff --git a/third_party/WebKit/Source/devtools/front_end/coverage/CoverageView.js b/third_party/WebKit/Source/devtools/front_end/coverage/CoverageView.js
index 084d40a..52156c4 100644
--- a/third_party/WebKit/Source/devtools/front_end/coverage/CoverageView.js
+++ b/third_party/WebKit/Source/devtools/front_end/coverage/CoverageView.js
@@ -33,12 +33,13 @@
     topToolbar.appendToolbarItem(this._clearButton);
 
     this._coverageResultsElement = this.contentElement.createChild('div', 'coverage-results');
-    this._progressElement = this._coverageResultsElement.createChild('div', 'progress-view');
+    this._landingPage = this._buildLandingPage();
+
     this._listView = new Coverage.CoverageListView();
 
     this._statusToolbarElement = this.contentElement.createChild('div', 'coverage-toolbar-summary');
     this._statusMessageElement = this._statusToolbarElement.createChild('div', 'coverage-message');
-    this._showHelpScreen();
+    this._landingPage.show(this._coverageResultsElement);
   }
 
   _reset() {
@@ -48,24 +49,25 @@
     }
     this._listView.reset();
     this._listView.detach();
-    this._coverageResultsElement.removeChildren();
-    this._showHelpScreen();
-
+    this._landingPage.show(this._coverageResultsElement);
     this._statusMessageElement.textContent = '';
   }
 
-  _showHelpScreen() {
-    this._coverageResultsElement.appendChild(this._progressElement);
-    this._progressElement.removeChildren();
-
-    var recordButton = UI.Toolbar.createActionButton(this._toggleRecordAction).element;
-    var reloadButton = UI.Toolbar.createActionButtonForId('coverage.start-with-reload').element;
-
-    this._progressElement.createChild('p', 'landing-page')
-        .appendChild(UI.formatLocalized(
-            'Click the record button %s to start capturing coverage.\n' +
-                'Click the reload button %s to reload and start capturing coverage.',
-            [recordButton, reloadButton]));
+  /**
+   * @return {!UI.VBox}
+   */
+  _buildLandingPage() {
+    var recordButton = UI.createInlineButton(UI.Toolbar.createActionButton(this._toggleRecordAction));
+    var reloadButton = UI.createInlineButton(UI.Toolbar.createActionButtonForId('coverage.start-with-reload'));
+    var widget = new UI.VBox();
+    var message = UI.formatLocalized(
+        'Click the record button %s to start capturing coverage.\n' +
+            'Click the reload button %s to reload and start capturing coverage.',
+        [recordButton, reloadButton]);
+    message.classList.add('message');
+    widget.contentElement.appendChild(message);
+    widget.element.classList.add('landing-page');
+    return widget;
   }
 
   _toggleRecording() {
@@ -102,7 +104,8 @@
     this._toggleRecordAction.setToggled(true);
     this._clearButton.setEnabled(false);
     this._startWithReloadButton.setEnabled(false);
-    this._coverageResultsElement.removeChildren();
+    if (this._landingPage.isShowing())
+      this._landingPage.detach();
     this._listView.show(this._coverageResultsElement);
     this._poll();
   }
diff --git a/third_party/WebKit/Source/devtools/front_end/coverage/coverageListView.css b/third_party/WebKit/Source/devtools/front_end/coverage/coverageListView.css
index 75c65c67..6f0bcaf1 100644
--- a/third_party/WebKit/Source/devtools/front_end/coverage/coverageListView.css
+++ b/third_party/WebKit/Source/devtools/front_end/coverage/coverageListView.css
@@ -51,3 +51,7 @@
   width: 45px;
   display: inline-block;
 }
+
+.data-grid:focus tr.selected span.percent-value {
+  color: #eee;
+}
diff --git a/third_party/WebKit/Source/devtools/front_end/coverage/coverageView.css b/third_party/WebKit/Source/devtools/front_end/coverage/coverageView.css
index 4ffd17b..816ef2a 100644
--- a/third_party/WebKit/Source/devtools/front_end/coverage/coverageView.css
+++ b/third_party/WebKit/Source/devtools/front_end/coverage/coverageView.css
@@ -41,34 +41,12 @@
     flex: auto;
 }
 
-.progress-view {
-    display: flex;
+.landing-page {
     justify-content: center;
-    align-items: center;
-    font-size: 30px;
+    align-items:  center;
+    padding: 20px;
 }
 
-.progress-view .landing-page {
-    flex: none;
-    overflow: auto;
-    font-size: 13px;
-    line-height: 15px;
-    color: #777;
+.landing-page .message {
     white-space: pre-line;
 }
-
-.progress-view .landing-page button {
-    padding: 0;
-    vertical-align: sub;
-    border: 1px solid #ddd;
-    margin-top: 4px;
-    background-color: #f3f3f3;
-}
-
-.progress-view .landing-page button  > span {
-    margin: -1px 2px -3px -2px;
-}
-
-.coverage-results > div {
-    flex: auto;
-}
diff --git a/third_party/WebKit/Source/devtools/front_end/sources/CallStackSidebarPane.js b/third_party/WebKit/Source/devtools/front_end/sources/CallStackSidebarPane.js
index def9c701..73503b4 100644
--- a/third_party/WebKit/Source/devtools/front_end/sources/CallStackSidebarPane.js
+++ b/third_party/WebKit/Source/devtools/front_end/sources/CallStackSidebarPane.js
@@ -296,8 +296,8 @@
     if (!location)
       return;
     if (item.debuggerCallFrame && UI.context.flavor(SDK.DebuggerModel.CallFrame) !== item.debuggerCallFrame) {
-      UI.context.setFlavor(SDK.DebuggerModel.CallFrame, item.debuggerCallFrame);
       this._debuggerModel.setSelectedCallFrame(item.debuggerCallFrame);
+      UI.context.setFlavor(SDK.DebuggerModel.CallFrame, item.debuggerCallFrame);
     } else {
       Common.Revealer.reveal(Bindings.debuggerWorkspaceBinding.rawLocationToUILocation(location));
     }
diff --git a/third_party/WebKit/Source/devtools/front_end/timeline/TimelinePanel.js b/third_party/WebKit/Source/devtools/front_end/timeline/TimelinePanel.js
index 08a9abf..cdba648 100644
--- a/third_party/WebKit/Source/devtools/front_end/timeline/TimelinePanel.js
+++ b/third_party/WebKit/Source/devtools/front_end/timeline/TimelinePanel.js
@@ -666,8 +666,8 @@
     this._landingPage.contentElement.classList.add('timeline-landing-page', 'fill');
     var centered = this._landingPage.contentElement.createChild('div');
 
-    var recordButton = UI.Toolbar.createActionButton(this._toggleRecordAction).element;
-    var reloadButton = UI.Toolbar.createActionButtonForId('main.reload').element;
+    var recordButton = UI.createInlineButton(UI.Toolbar.createActionButton(this._toggleRecordAction));
+    var reloadButton = UI.createInlineButton(UI.Toolbar.createActionButtonForId('main.reload'));
 
     centered.createChild('p').appendChild(UI.formatLocalized(
         'Click the record button %s or hit %s to capture a new recording.\n' +
diff --git a/third_party/WebKit/Source/devtools/front_end/timeline/timelinePanel.css b/third_party/WebKit/Source/devtools/front_end/timeline/timelinePanel.css
index 33979b9..c588327 100644
--- a/third_party/WebKit/Source/devtools/front_end/timeline/timelinePanel.css
+++ b/third_party/WebKit/Source/devtools/front_end/timeline/timelinePanel.css
@@ -639,22 +639,6 @@
     white-space: pre-line;
 }
 
-.timeline-landing-page button {
-    padding: 0;
-    vertical-align: sub;
-    border: 1px solid #ddd;
-    margin-top: 4px;
-    background-color: #f3f3f3;
-}
-
-.timeline-landing-page button > span {
-    margin: -1px 2px -3px -2px;
-}
-
-.timeline-landing-page button > span:hover {
-    background-color: #333;
-}
-
 .timeline-landing-warning {
     background-color: #fffde7;
     padding: 16px 20px;
diff --git a/third_party/WebKit/Source/devtools/front_end/ui/ListControl.js b/third_party/WebKit/Source/devtools/front_end/ui/ListControl.js
index b55c2034..9e3da79b 100644
--- a/third_party/WebKit/Source/devtools/front_end/ui/ListControl.js
+++ b/third_party/WebKit/Source/devtools/front_end/ui/ListControl.js
@@ -124,6 +124,23 @@
   }
 
   /**
+   * @param {T} item
+   * @param {function(T, T):number} comparator
+   */
+  insertItemWithComparator(item, comparator) {
+    var index = this._items.lowerBound(item, comparator);
+    this.insertItemAtIndex(index, item);
+  }
+
+  /**
+   * @param {T} item
+   * @return {number}
+   */
+  indexOfItem(item) {
+    return this._items.indexOf(item);
+  }
+
+  /**
    * @param {number} index
    * @return {T}
    */
@@ -138,8 +155,10 @@
    */
   removeItem(item) {
     var index = this._items.indexOf(item);
-    if (index === -1)
-      throw 'Attempt to remove non-existing item';
+    if (index === -1) {
+      console.error('Attempt to remove non-existing item');
+      return;
+    }
     this.removeItemAtIndex(index);
   }
 
@@ -181,6 +200,22 @@
     this.replaceItemsInRange(0, this._items.length, items);
   }
 
+  refreshAllItems() {
+    this.refreshItemsInRange(0, this._items.length);
+  }
+
+  /**
+   * @param {number} from
+   * @param {number} to
+   */
+  refreshItemsInRange(from, to) {
+    for (var i = from; i < to; i++)
+      this._itemToElement.delete(this._items[i]);
+    this.invalidateRange(from, to);
+    if (this._selectedIndex !== -1)
+      this._select(this._selectedIndex, null, null);
+  }
+
   /**
    * @param {number} from
    * @param {number} to
@@ -200,8 +235,10 @@
   }
 
   invalidateItemHeight() {
-    if (this._mode !== UI.ListMode.EqualHeightItems)
-      throw 'Only supported in equal height items mode';
+    if (this._mode !== UI.ListMode.EqualHeightItems) {
+      console.error('Only supported in equal height items mode');
+      return;
+    }
     this._fixedHeight = 0;
     if (this._items.length) {
       this._itemToElement.clear();
@@ -229,8 +266,10 @@
    */
   scrollItemIntoView(item, center) {
     var index = this._items.indexOf(item);
-    if (index === -1)
-      throw 'Attempt to scroll onto missing item';
+    if (index === -1) {
+      console.error('Attempt to scroll onto missing item');
+      return;
+    }
     this._scrollIntoView(index, center);
   }
 
@@ -242,21 +281,33 @@
   }
 
   /**
+   * @return {number}
+   */
+  selectedIndex() {
+    return this._selectedIndex;
+  }
+
+  /**
    * @param {?T} item
    * @param {boolean=} center
+   * @param {boolean=} dontScroll
    */
-  selectItem(item, center) {
+  selectItem(item, center, dontScroll) {
     var index = -1;
     if (item !== null) {
       index = this._items.indexOf(item);
-      if (index === -1)
-        throw 'Attempt to select missing item';
-      if (!this._delegate.isItemSelectable(item))
-        throw 'Attempt to select non-selectable item';
+      if (index === -1) {
+        console.error('Attempt to select missing item');
+        return;
+      }
+      if (!this._delegate.isItemSelectable(item)) {
+        console.error('Attempt to select non-selectable item');
+        return;
+      }
     }
     if (this._selectedIndex !== index)
       this._select(index);
-    if (index !== -1)
+    if (index !== -1 && !dontScroll)
       this._scrollIntoView(index, center);
   }
 
@@ -595,8 +646,10 @@
   }
 
   _clearViewport() {
-    if (this._mode === UI.ListMode.NonViewport)
-      throw 'There should be no viewport updates in non-viewport mode';
+    if (this._mode === UI.ListMode.NonViewport) {
+      console.error('There should be no viewport updates in non-viewport mode');
+      return;
+    }
     this._firstIndex = 0;
     this._lastIndex = 0;
     this._renderedHeight = 0;
@@ -620,9 +673,10 @@
    */
   _updateViewport(scrollTop, viewportHeight) {
     // Note: this method should not force layout. Be careful.
-    if (this._mode === UI.ListMode.NonViewport)
-      throw 'There should be no viewport updates in non-viewport mode';
-
+    if (this._mode === UI.ListMode.NonViewport) {
+      console.error('There should be no viewport updates in non-viewport mode');
+      return;
+    }
     var totalHeight = this._totalHeight();
     if (!totalHeight) {
       this._firstIndex = 0;
diff --git a/third_party/WebKit/Source/devtools/front_end/ui/UIUtils.js b/third_party/WebKit/Source/devtools/front_end/ui/UIUtils.js
index 66d61ac9..d952835 100644
--- a/third_party/WebKit/Source/devtools/front_end/ui/UIUtils.js
+++ b/third_party/WebKit/Source/devtools/front_end/ui/UIUtils.js
@@ -2014,3 +2014,17 @@
     buttonsBar.appendChild(UI.createTextButton(Common.UIString('Cancel'), cancelCallback));
   }
 };
+
+/**
+ * @param {!UI.ToolbarToggle} toolbarButton
+ * @return {!Element}
+ */
+UI.createInlineButton = function(toolbarButton) {
+  var element = createElement('span');
+  var shadowRoot = UI.createShadowRootWithCoreStyles(element, 'ui/inlineButton.css');
+  element.classList.add('inline-button');
+  var toolbar = new UI.Toolbar('');
+  toolbar.appendToolbarItem(toolbarButton);
+  shadowRoot.appendChild(toolbar.element);
+  return element;
+};
diff --git a/third_party/WebKit/Source/devtools/front_end/ui/inlineButton.css b/third_party/WebKit/Source/devtools/front_end/ui/inlineButton.css
new file mode 100644
index 0000000..53622ea9
--- /dev/null
+++ b/third_party/WebKit/Source/devtools/front_end/ui/inlineButton.css
@@ -0,0 +1,21 @@
+/*
+ * 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.
+ */
+
+:host {
+  display: inline-block;
+  border: 1px solid #ddd;
+  position: relative;
+  top: 7px;
+  margin: 2px;
+  background-color: #f3f3f3;
+}
+
+:host > * {
+  position: relative;
+  left: -2px;
+  width: 28px;
+  height: 26px;
+}
\ No newline at end of file
diff --git a/third_party/WebKit/Source/devtools/front_end/ui/module.json b/third_party/WebKit/Source/devtools/front_end/ui/module.json
index 20eca6df..52967e3f 100644
--- a/third_party/WebKit/Source/devtools/front_end/ui/module.json
+++ b/third_party/WebKit/Source/devtools/front_end/ui/module.json
@@ -61,6 +61,7 @@
         "filter.css",
         "glassPane.css",
         "infobar.css",
+        "inlineButton.css",
         "inspectorCommon.css",
         "inspectorStyle.css",
         "inspectorSyntaxHighlight.css",
diff --git a/third_party/WebKit/Source/devtools/front_end/ui/toolbar.css b/third_party/WebKit/Source/devtools/front_end/ui/toolbar.css
index 3958872b..1f79252 100644
--- a/third_party/WebKit/Source/devtools/front_end/ui/toolbar.css
+++ b/third_party/WebKit/Source/devtools/front_end/ui/toolbar.css
@@ -13,6 +13,7 @@
     position: relative;
     white-space: nowrap;
     height: 26px;
+    contain: strict;
     overflow: hidden;
     z-index: 12;
     display: flex;
@@ -23,6 +24,7 @@
 .toolbar-shadow.wrappable {
     flex-wrap: wrap;
     overflow: visible;
+    contain: none;
 }
 
 .toolbar-shadow.wrappable-reverse {
@@ -36,6 +38,7 @@
 .toolbar-shadow.vertical {
     flex-direction: column;
     height: auto;
+    contain: none;
     align-items: flex-start;
 }
 
@@ -296,15 +299,10 @@
 .toolbar-shadow.floating {
     flex-direction: column;
     height: auto;
+    contain: none;
     background-color: white;
     border: 1px solid #ccc;
     margin-top: -1px;
     width: 28px;
     left: -2px;
 }
-
-span.toolbar-select-container.toolbar-item.warning {
-    background: #ffd7d7;
-    padding: 0 5px 0 0;
-    margin-right: 1px;
-}
diff --git a/third_party/WebKit/Source/modules/accessibility/AXLayoutObject.cpp b/third_party/WebKit/Source/modules/accessibility/AXLayoutObject.cpp
index 503fd0b..1af63dc 100644
--- a/third_party/WebKit/Source/modules/accessibility/AXLayoutObject.cpp
+++ b/third_party/WebKit/Source/modules/accessibility/AXLayoutObject.cpp
@@ -1084,23 +1084,30 @@
   if (!GetLayoutObject())
     return nullptr;
 
-  InlineBox* inline_box = nullptr;
-  if (GetLayoutObject()->IsLayoutInline())
-    inline_box = ToLayoutInline(GetLayoutObject())->LastLineBox();
-  else if (GetLayoutObject()->IsText())
-    inline_box = ToLayoutText(GetLayoutObject())->LastTextBox();
-
-  if (!inline_box)
-    return nullptr;
-
   AXObject* result = nullptr;
-  for (InlineBox* next = inline_box->NextOnLine(); next;
-       next = next->NextOnLine()) {
-    LayoutObject* layout_object =
-        LineLayoutAPIShim::LayoutObjectFrom(next->GetLineLayoutItem());
-    result = AxObjectCache().GetOrCreate(layout_object);
-    if (result)
-      break;
+  if (GetLayoutObject()->IsListMarker()) {
+    AXObject* next_sibling = RawNextSibling();
+    if (!next_sibling || !next_sibling->Children().size())
+      return nullptr;
+    result = next_sibling->Children()[0].Get();
+  } else {
+    InlineBox* inline_box = nullptr;
+    if (GetLayoutObject()->IsLayoutInline())
+      inline_box = ToLayoutInline(GetLayoutObject())->LastLineBox();
+    else if (GetLayoutObject()->IsText())
+      inline_box = ToLayoutText(GetLayoutObject())->LastTextBox();
+
+    if (!inline_box)
+      return nullptr;
+
+    for (InlineBox* next = inline_box->NextOnLine(); next;
+         next = next->NextOnLine()) {
+      LayoutObject* layout_object =
+          LineLayoutAPIShim::LayoutObjectFrom(next->GetLineLayoutItem());
+      result = AxObjectCache().GetOrCreate(layout_object);
+      if (result)
+        break;
+    }
   }
 
   // A static text node might span multiple lines. Try to return the first
diff --git a/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.cpp b/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.cpp
index aac68e9..1294059 100644
--- a/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.cpp
+++ b/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.cpp
@@ -5261,8 +5261,8 @@
     // SW path.
 
     if (video->CopyVideoTextureToPlatformTexture(
-            ContextGL(), texture->Object(), internalformat, format, type,
-            unpack_premultiply_alpha_, unpack_flip_y_)) {
+            ContextGL(), target, texture->Object(), internalformat, format,
+            type, level, unpack_premultiply_alpha_, unpack_flip_y_)) {
       texture->UpdateLastUploadedVideo(video->GetWebMediaPlayer());
       return;
     }
diff --git a/third_party/WebKit/Source/platform/PODRedBlackTree.h b/third_party/WebKit/Source/platform/PODRedBlackTree.h
index 0edbe96d..fe71ae1 100644
--- a/third_party/WebKit/Source/platform/PODRedBlackTree.h
+++ b/third_party/WebKit/Source/platform/PODRedBlackTree.h
@@ -138,7 +138,7 @@
   // Constructs a new red-black tree, allocating temporary objects
   // from the given PODArena.
   explicit PODRedBlackTree(PassRefPtr<PODFreeListArena<Node>> arena)
-      : arena_(arena),
+      : arena_(std::move(arena)),
         root_(0),
         needs_full_ordering_comparisons_(false)
 #ifndef NDEBUG
diff --git a/third_party/WebKit/Source/platform/exported/WebScrollbarThemePainter.cpp b/third_party/WebKit/Source/platform/exported/WebScrollbarThemePainter.cpp
index 0b8d9fa..c7b162c 100644
--- a/third_party/WebKit/Source/platform/exported/WebScrollbarThemePainter.cpp
+++ b/third_party/WebKit/Source/platform/exported/WebScrollbarThemePainter.cpp
@@ -54,7 +54,7 @@
   ~ScopedScrollbarPainter() {
     canvas_->save();
     canvas_->translate(rect_.x, rect_.y);
-    canvas_->PlaybackPaintRecord(builder_.EndRecording());
+    canvas_->drawPicture(builder_.EndRecording());
     canvas_->restore();
   }
 
diff --git a/third_party/WebKit/Source/platform/graphics/GraphicsLayer.cpp b/third_party/WebKit/Source/platform/graphics/GraphicsLayer.cpp
index 20054d2..116a3de 100644
--- a/third_party/WebKit/Source/platform/graphics/GraphicsLayer.cpp
+++ b/third_party/WebKit/Source/platform/graphics/GraphicsLayer.cpp
@@ -286,7 +286,7 @@
           GetRasterInvalidationTrackingMap().Add(this);
       tracking.last_painted_record = std::move(record);
       tracking.last_interest_rect = previous_interest_rect_;
-      tracking.raster_invalidation_region_since_last_paint = Region();
+      tracking.invalidation_region_since_last_paint = Region();
     }
   }
 }
@@ -482,14 +482,14 @@
     return;
 
   if (RuntimeEnabledFeatures::paintUnderInvalidationCheckingEnabled())
-    tracking->tracked_raster_invalidations.clear();
+    tracking->invalidations.clear();
   else
     GetRasterInvalidationTrackingMap().Remove(this);
 }
 
 bool GraphicsLayer::HasTrackedRasterInvalidations() const {
   if (auto* tracking = GetRasterInvalidationTracking())
-    return !tracking->tracked_raster_invalidations.IsEmpty();
+    return !tracking->invalidations.IsEmpty();
   return false;
 }
 
@@ -513,7 +513,7 @@
     info.client_debug_name = client.DebugName();
     info.rect = rect;
     info.reason = reason;
-    tracking.tracked_raster_invalidations.push_back(info);
+    tracking.invalidations.push_back(info);
   }
 
   if (RuntimeEnabledFeatures::paintUnderInvalidationCheckingEnabled()) {
@@ -521,7 +521,7 @@
     // invalidation rect.
     IntRect r = rect;
     r.Inflate(1);
-    tracking.raster_invalidation_region_since_last_paint.Unite(r);
+    tracking.invalidation_region_since_last_paint.Unite(r);
   }
 }
 
@@ -1252,13 +1252,12 @@
       SkColor old_pixel = old_bitmap.getColor(bitmap_x, bitmap_y);
       SkColor new_pixel = new_bitmap.getColor(bitmap_x, bitmap_y);
       if (PixelsDiffer(old_pixel, new_pixel) &&
-          !tracking->raster_invalidation_region_since_last_paint.Contains(
+          !tracking->invalidation_region_since_last_paint.Contains(
               IntPoint(layer_x, layer_y))) {
         if (mismatching_pixels < kMaxMismatchesToReport) {
-          UnderPaintInvalidation under_paint_invalidation = {
-              layer_x, layer_y, old_pixel, new_pixel};
-          tracking->under_paint_invalidations.push_back(
-              under_paint_invalidation);
+          UnderRasterInvalidation under_invalidation = {layer_x, layer_y,
+                                                        old_pixel, new_pixel};
+          tracking->under_invalidations.push_back(under_invalidation);
           LOG(ERROR) << DebugName()
                      << " Uninvalidated old/new pixels mismatch at " << layer_x
                      << "," << layer_y << " old:" << std::hex << old_pixel
diff --git a/third_party/WebKit/Source/platform/graphics/RecordingImageBufferSurface.cpp b/third_party/WebKit/Source/platform/graphics/RecordingImageBufferSurface.cpp
index 6d3431f..c7eebf1 100644
--- a/third_party/WebKit/Source/platform/graphics/RecordingImageBufferSurface.cpp
+++ b/third_party/WebKit/Source/platform/graphics/RecordingImageBufferSurface.cpp
@@ -105,14 +105,14 @@
   fallback_surface_->SetImageBuffer(image_buffer_);
 
   if (previous_frame_) {
-    fallback_surface_->Canvas()->PlaybackPaintRecord(previous_frame_);
+    fallback_surface_->Canvas()->drawPicture(previous_frame_);
     previous_frame_.reset();
   }
 
   if (current_frame_) {
     sk_sp<PaintRecord> record = current_frame_->finishRecordingAsPicture();
     if (record)
-      fallback_surface_->Canvas()->PlaybackPaintRecord(record);
+      fallback_surface_->Canvas()->drawPicture(record);
     current_frame_.reset();
   }
 
diff --git a/third_party/WebKit/Source/platform/graphics/compositing/PaintArtifactCompositor.cpp b/third_party/WebKit/Source/platform/graphics/compositing/PaintArtifactCompositor.cpp
index 0aaecc29..612385a 100644
--- a/third_party/WebKit/Source/platform/graphics/compositing/PaintArtifactCompositor.cpp
+++ b/third_party/WebKit/Source/platform/graphics/compositing/PaintArtifactCompositor.cpp
@@ -91,7 +91,7 @@
       return;
 
     if (RuntimeEnabledFeatures::paintUnderInvalidationCheckingEnabled())
-      tracking->tracked_raster_invalidations.clear();
+      tracking->invalidations.clear();
     else
       CcLayersRasterInvalidationTrackingMap().Remove(cc_picture_layer_.get());
   }
@@ -100,28 +100,28 @@
     RasterInvalidationTracking* tracking =
         CcLayersRasterInvalidationTrackingMap().Find(cc_picture_layer_.get());
     if (tracking)
-      return !tracking->tracked_raster_invalidations.IsEmpty();
+      return !tracking->invalidations.IsEmpty();
     return false;
   }
 
-  void SetNeedsDisplayRect(const gfx::Rect& rect,
-                           RasterInvalidationInfo* raster_invalidation_info) {
+  void SetNeedsDisplayRect(const gfx::Rect& rect) {
     cc_picture_layer_->SetNeedsDisplayRect(rect);
+  }
 
-    if (!raster_invalidation_info || rect.IsEmpty())
-      return;
-
-    RasterInvalidationTracking& tracking =
+  void AddTrackedRasterInvalidations(
+      const RasterInvalidationTracking& tracking) {
+    auto& cc_tracking =
         CcLayersRasterInvalidationTrackingMap().Add(cc_picture_layer_.get());
+    cc_tracking.invalidations.AppendVector(tracking.invalidations);
 
-    tracking.tracked_raster_invalidations.push_back(*raster_invalidation_info);
-
-    if (RuntimeEnabledFeatures::paintUnderInvalidationCheckingEnabled()) {
+    if (!RuntimeEnabledFeatures::paintUnderInvalidationCheckingEnabled())
+      return;
+    for (const auto& info : tracking.invalidations) {
       // TODO(crbug.com/496260): Some antialiasing effects overflow the paint
       // invalidation rect.
-      IntRect r = raster_invalidation_info->rect;
+      IntRect r = info.rect;
       r.Inflate(1);
-      tracking.raster_invalidation_region_since_last_paint.Unite(r);
+      cc_tracking.invalidation_region_since_last_paint.Unite(r);
     }
   }
 
@@ -171,17 +171,10 @@
   root_layer_ = cc::Layer::Create();
   web_layer_ = Platform::Current()->CompositorSupport()->CreateLayerFromCCLayer(
       root_layer_.get());
-  is_tracking_raster_invalidations_ = false;
 }
 
 PaintArtifactCompositor::~PaintArtifactCompositor() {}
 
-void PaintArtifactCompositor::SetTracksRasterInvalidations(
-    bool tracks_paint_invalidations) {
-  ResetTrackedRasterInvalidations();
-  is_tracking_raster_invalidations_ = tracks_paint_invalidations;
-}
-
 void PaintArtifactCompositor::ResetTrackedRasterInvalidations() {
   for (auto& client : content_layer_clients_)
     client->ResetTrackedRasterInvalidations();
@@ -289,12 +282,6 @@
   content_layer_client->ClearPaintChunkDebugData();
 
   for (const auto& paint_chunk : pending_layer.paint_chunks) {
-    RasterInvalidationTracking* raster_tracking =
-        tracking_map ? tracking_map->Find(paint_chunk) : nullptr;
-    DCHECK(!raster_tracking ||
-           raster_tracking->tracked_raster_invalidations.size() ==
-               paint_chunk->raster_invalidation_rects.size());
-
     if (store_debug_info) {
       content_layer_client->AddPaintChunkDebugData(
           paint_artifact.GetDisplayItemList().SubsequenceAsJSON(
@@ -303,10 +290,8 @@
                   DisplayItemList::kShownOnlyDisplayItemTypes));
     }
 
-    for (unsigned index = 0;
-         index < paint_chunk->raster_invalidation_rects.size(); ++index) {
-      IntRect rect(
-          EnclosingIntRect(paint_chunk->raster_invalidation_rects[index]));
+    for (const auto& r : paint_chunk->raster_invalidation_rects) {
+      IntRect rect(EnclosingIntRect(r));
       gfx::Rect cc_invalidation_rect(rect.X(), rect.Y(),
                                      std::max(0, rect.Width()),
                                      std::max(0, rect.Height()));
@@ -315,12 +300,12 @@
       // Raster paintChunk.rasterInvalidationRects is in the space of the
       // containing transform node, so need to subtract off the layer offset.
       cc_invalidation_rect.Offset(-cc_combined_bounds.OffsetFromOrigin());
-      content_layer_client->SetNeedsDisplayRect(
-          cc_invalidation_rect,
-          raster_tracking
-              ? &raster_tracking->tracked_raster_invalidations[index]
-              : nullptr);
+      content_layer_client->SetNeedsDisplayRect(cc_invalidation_rect);
     }
+
+    if (auto* raster_tracking =
+            tracking_map ? tracking_map->Find(paint_chunk) : nullptr)
+      content_layer_client->AddTrackedRasterInvalidations(*raster_tracking);
   }
 
   new_content_layer_clients.push_back(std::move(content_layer_client));
diff --git a/third_party/WebKit/Source/platform/graphics/compositing/PaintArtifactCompositor.h b/third_party/WebKit/Source/platform/graphics/compositing/PaintArtifactCompositor.h
index 73547d6..ad3a660 100644
--- a/third_party/WebKit/Source/platform/graphics/compositing/PaintArtifactCompositor.h
+++ b/third_party/WebKit/Source/platform/graphics/compositing/PaintArtifactCompositor.h
@@ -81,7 +81,6 @@
     return extra_data_for_testing_.get();
   }
 
-  void SetTracksRasterInvalidations(bool);
   void ResetTrackedRasterInvalidations();
   bool HasTrackedRasterInvalidations() const;
 
@@ -178,7 +177,6 @@
   std::unique_ptr<ExtraDataForTesting> extra_data_for_testing_;
   friend class StubChromeClientForSPv2;
 
-  bool is_tracking_raster_invalidations_;
   FRIEND_TEST_ALL_PREFIXES(PaintArtifactCompositorTestWithPropertyTrees,
                            ForeignLayerPassesThrough);
   FRIEND_TEST_ALL_PREFIXES(PaintArtifactCompositorTestWithPropertyTrees,
diff --git a/third_party/WebKit/Source/platform/graphics/paint/PaintController.cpp b/third_party/WebKit/Source/platform/graphics/paint/PaintController.cpp
index f39d34c..4728fb0c 100644
--- a/third_party/WebKit/Source/platform/graphics/paint/PaintController.cpp
+++ b/third_party/WebKit/Source/platform/graphics/paint/PaintController.cpp
@@ -23,10 +23,10 @@
 void PaintController::SetTracksRasterInvalidations(bool value) {
   if (value ||
       RuntimeEnabledFeatures::paintUnderInvalidationCheckingEnabled()) {
-    paint_chunks_raster_invalidation_tracking_map_ =
+    raster_invalidation_tracking_map_ =
         WTF::WrapUnique(new RasterInvalidationTrackingMap<const PaintChunk>);
   } else {
-    paint_chunks_raster_invalidation_tracking_map_ = nullptr;
+    raster_invalidation_tracking_map_ = nullptr;
   }
 }
 
@@ -252,9 +252,10 @@
     size_t last_chunk_index = new_paint_chunks_.LastChunkIndex();
     if (new_paint_chunks_.IncrementDisplayItemIndex(display_item)) {
       DCHECK(last_chunk_index != new_paint_chunks_.LastChunkIndex());
-      if (last_chunk_index != kNotFound)
-        GenerateChunkRasterInvalidationRects(
+      if (last_chunk_index != kNotFound) {
+        GenerateRasterInvalidations(
             new_paint_chunks_.PaintChunkAt(last_chunk_index));
+      }
     }
   }
 
@@ -540,7 +541,7 @@
 
   if (RuntimeEnabledFeatures::slimmingPaintV2Enabled() &&
       !new_display_item_list_.IsEmpty())
-    GenerateChunkRasterInvalidationRects(new_paint_chunks_.LastChunk());
+    GenerateRasterInvalidations(new_paint_chunks_.LastChunk());
 
   int num_slow_paths = 0;
 
@@ -599,9 +600,9 @@
   // The new list will not be appended to again so we can release unused memory.
   new_display_item_list_.ShrinkToFit();
 
-  if (paint_chunks_raster_invalidation_tracking_map_) {
+  if (raster_invalidation_tracking_map_) {
     for (const auto& chunk : current_paint_artifact_.PaintChunks())
-      paint_chunks_raster_invalidation_tracking_map_->Remove(&chunk);
+      raster_invalidation_tracking_map_->Remove(&chunk);
   }
   current_paint_artifact_ = PaintArtifact(
       std::move(new_display_item_list_), new_paint_chunks_.ReleasePaintChunks(),
@@ -674,8 +675,7 @@
       VisualRectForDisplayItem(display_item, offset_from_layout_object));
 }
 
-void PaintController::GenerateChunkRasterInvalidationRects(
-    PaintChunk& new_chunk) {
+void PaintController::GenerateRasterInvalidations(PaintChunk& new_chunk) {
   DCHECK(RuntimeEnabledFeatures::slimmingPaintV2Enabled());
   if (new_chunk.begin_index >=
       current_cached_subsequence_begin_index_in_new_list_)
@@ -683,7 +683,7 @@
 
   static FloatRect infinite_float_rect(LayoutRect::InfiniteIntRect());
   if (!new_chunk.id) {
-    AddRasterInvalidationInfo(nullptr, new_chunk, infinite_float_rect);
+    AddRasterInvalidation(nullptr, new_chunk, infinite_float_rect);
     return;
   }
 
@@ -692,8 +692,7 @@
   while (next_chunk_to_match_ < old_chunks.size()) {
     const PaintChunk& old_chunk = old_chunks[next_chunk_to_match_];
     if (new_chunk.Matches(old_chunk)) {
-      GenerateChunkRasterInvalidationRectsComparingOldChunk(new_chunk,
-                                                            old_chunk);
+      GenerateRasterInvalidationsComparingChunks(new_chunk, old_chunk);
       ++next_chunk_to_match_;
       return;
     }
@@ -717,23 +716,29 @@
   if (it != out_of_order_chunk_indices_.end()) {
     for (size_t i : it->value) {
       if (new_chunk.Matches(old_chunks[i])) {
-        GenerateChunkRasterInvalidationRectsComparingOldChunk(new_chunk,
-                                                              old_chunks[i]);
+        GenerateRasterInvalidationsComparingChunks(new_chunk, old_chunks[i]);
         return;
       }
     }
   }
 
   // We reach here because the chunk is new.
-  AddRasterInvalidationInfo(nullptr, new_chunk, infinite_float_rect);
+  AddRasterInvalidation(nullptr, new_chunk, infinite_float_rect);
 }
 
-void PaintController::AddRasterInvalidationInfo(const DisplayItemClient* client,
-                                                PaintChunk& chunk,
-                                                const FloatRect& rect) {
+void PaintController::AddRasterInvalidation(const DisplayItemClient* client,
+                                            PaintChunk& chunk,
+                                            const FloatRect& rect) {
   chunk.raster_invalidation_rects.push_back(rect);
-  if (!paint_chunks_raster_invalidation_tracking_map_)
-    return;
+  if (raster_invalidation_tracking_map_)
+    TrackRasterInvalidation(client, chunk, rect);
+}
+
+void PaintController::TrackRasterInvalidation(const DisplayItemClient* client,
+                                              PaintChunk& chunk,
+                                              const FloatRect& rect) {
+  DCHECK(raster_invalidation_tracking_map_);
+
   RasterInvalidationInfo info;
   info.rect = EnclosingIntRect(rect);
   info.client = client;
@@ -741,12 +746,10 @@
     info.client_debug_name = client->DebugName();
     info.reason = client->GetPaintInvalidationReason();
   }
-  RasterInvalidationTracking& tracking =
-      paint_chunks_raster_invalidation_tracking_map_->Add(&chunk);
-  tracking.tracked_raster_invalidations.push_back(info);
+  raster_invalidation_tracking_map_->Add(&chunk).invalidations.push_back(info);
 }
 
-void PaintController::GenerateChunkRasterInvalidationRectsComparingOldChunk(
+void PaintController::GenerateRasterInvalidationsComparingChunks(
     PaintChunk& new_chunk,
     const PaintChunk& old_chunk) {
   DCHECK(RuntimeEnabledFeatures::slimmingPaintV2Enabled());
@@ -774,9 +777,8 @@
           // And invalidate in the new chunk into which the item was moved.
           PaintChunk& moved_to_chunk =
               new_paint_chunks_.FindChunkByDisplayItemIndex(moved_to_index);
-          AddRasterInvalidationInfo(
-              client_to_invalidate, moved_to_chunk,
-              FloatRect(client_to_invalidate->VisualRect()));
+          AddRasterInvalidation(client_to_invalidate, moved_to_chunk,
+                                FloatRect(client_to_invalidate->VisualRect()));
         } else if (moved_to_index < highest_moved_to_index) {
           // The item has been moved behind other cached items, so need to
           // invalidate the area that is probably exposed by the item moved
@@ -794,7 +796,7 @@
     if (client_to_invalidate &&
         invalidated_clients_in_old_chunk.insert(client_to_invalidate)
             .is_new_entry) {
-      AddRasterInvalidationInfo(
+      AddRasterInvalidation(
           is_potentially_invalid_client ? nullptr : client_to_invalidate,
           new_chunk,
           FloatRect(current_paint_artifact_.GetDisplayItemList().VisualRect(
@@ -809,8 +811,8 @@
     if (new_item.DrawsContent() && !ClientCacheIsValid(new_item.Client()) &&
         invalidated_clients_in_new_chunk.insert(&new_item.Client())
             .is_new_entry) {
-      AddRasterInvalidationInfo(&new_item.Client(), new_chunk,
-                                FloatRect(new_item.Client().VisualRect()));
+      AddRasterInvalidation(&new_item.Client(), new_chunk,
+                            FloatRect(new_item.Client().VisualRect()));
     }
   }
 }
diff --git a/third_party/WebKit/Source/platform/graphics/paint/PaintController.h b/third_party/WebKit/Source/platform/graphics/paint/PaintController.h
index 5bfc86e..62d51c0 100644
--- a/third_party/WebKit/Source/platform/graphics/paint/PaintController.h
+++ b/third_party/WebKit/Source/platform/graphics/paint/PaintController.h
@@ -195,7 +195,7 @@
   void SetTracksRasterInvalidations(bool value);
   RasterInvalidationTrackingMap<const PaintChunk>*
   PaintChunksRasterInvalidationTrackingMap() {
-    return paint_chunks_raster_invalidation_tracking_map_.get();
+    return raster_invalidation_tracking_map_.get();
   }
 
 #if CHECK_DISPLAY_ITEM_CLIENT_ALIVENESS
@@ -280,13 +280,15 @@
   // newly created, or is changed causing the previous indices to be invalid.
   void ResetCurrentListIndices();
 
-  void GenerateChunkRasterInvalidationRects(PaintChunk& new_chunk);
-  void GenerateChunkRasterInvalidationRectsComparingOldChunk(
-      PaintChunk& new_chunk,
-      const PaintChunk& old_chunk);
-  void AddRasterInvalidationInfo(const DisplayItemClient*,
-                                 PaintChunk&,
-                                 const FloatRect&);
+  void GenerateRasterInvalidations(PaintChunk& new_chunk);
+  void GenerateRasterInvalidationsComparingChunks(PaintChunk& new_chunk,
+                                                  const PaintChunk& old_chunk);
+  inline void AddRasterInvalidation(const DisplayItemClient*,
+                                    PaintChunk&,
+                                    const FloatRect&);
+  void TrackRasterInvalidation(const DisplayItemClient*,
+                               PaintChunk&,
+                               const FloatRect&);
 
   // The following two methods are for checking under-invalidations
   // (when RuntimeEnabledFeatures::paintUnderInvalidationCheckingEnabled).
@@ -411,7 +413,7 @@
   String under_invalidation_message_prefix_;
 
   std::unique_ptr<RasterInvalidationTrackingMap<const PaintChunk>>
-      paint_chunks_raster_invalidation_tracking_map_;
+      raster_invalidation_tracking_map_;
 
 #if CHECK_DISPLAY_ITEM_CLIENT_ALIVENESS
   // A stack recording subsequence clients that are currently painting.
diff --git a/third_party/WebKit/Source/platform/graphics/paint/RasterInvalidationTracking.cpp b/third_party/WebKit/Source/platform/graphics/paint/RasterInvalidationTracking.cpp
index 0ad81f76..0b13563 100644
--- a/third_party/WebKit/Source/platform/graphics/paint/RasterInvalidationTracking.cpp
+++ b/third_party/WebKit/Source/platform/graphics/paint/RasterInvalidationTracking.cpp
@@ -41,12 +41,11 @@
 }
 
 void RasterInvalidationTracking::AsJSON(JSONObject* json) {
-  if (!tracked_raster_invalidations.IsEmpty()) {
-    std::sort(tracked_raster_invalidations.begin(),
-              tracked_raster_invalidations.end(),
+  if (!invalidations.IsEmpty()) {
+    std::sort(invalidations.begin(), invalidations.end(),
               &CompareRasterInvalidationInfo);
     std::unique_ptr<JSONArray> paint_invalidations_json = JSONArray::Create();
-    for (auto& info : tracked_raster_invalidations) {
+    for (auto& info : invalidations) {
       std::unique_ptr<JSONObject> info_json = JSONObject::Create();
       info_json->SetString("object", info.client_debug_name);
       if (!info.rect.IsEmpty()) {
@@ -62,10 +61,10 @@
     json->SetArray("paintInvalidations", std::move(paint_invalidations_json));
   }
 
-  if (!under_paint_invalidations.IsEmpty()) {
+  if (!under_invalidations.IsEmpty()) {
     std::unique_ptr<JSONArray> under_paint_invalidations_json =
         JSONArray::Create();
-    for (auto& under_paint_invalidation : under_paint_invalidations) {
+    for (auto& under_paint_invalidation : under_invalidations) {
       std::unique_ptr<JSONObject> under_paint_invalidation_json =
           JSONObject::Create();
       under_paint_invalidation_json->SetDouble("x", under_paint_invalidation.x);
diff --git a/third_party/WebKit/Source/platform/graphics/paint/RasterInvalidationTracking.h b/third_party/WebKit/Source/platform/graphics/paint/RasterInvalidationTracking.h
index 945cc82c..aeb1d123 100644
--- a/third_party/WebKit/Source/platform/graphics/paint/RasterInvalidationTracking.h
+++ b/third_party/WebKit/Source/platform/graphics/paint/RasterInvalidationTracking.h
@@ -5,6 +5,7 @@
 #ifndef RasterInvalidationTracking_h
 #define RasterInvalidationTracking_h
 
+#include "platform/RuntimeEnabledFeatures.h"
 #include "platform/geometry/IntRect.h"
 #include "platform/geometry/Region.h"
 #include "platform/graphics/PaintInvalidationReason.h"
@@ -22,11 +23,10 @@
   DISALLOW_NEW_EXCEPT_PLACEMENT_NEW();
   // This is for comparison only. Don't dereference because the client may have
   // died.
-  const DisplayItemClient* client;
+  const DisplayItemClient* client = nullptr;
   String client_debug_name;
   IntRect rect;
-  PaintInvalidationReason reason;
-  RasterInvalidationInfo() : reason(kPaintInvalidationFull) {}
+  PaintInvalidationReason reason = kPaintInvalidationFull;
 };
 
 inline bool operator==(const RasterInvalidationInfo& a,
@@ -34,7 +34,7 @@
   return a.rect == b.rect;
 }
 
-struct UnderPaintInvalidation {
+struct UnderRasterInvalidation {
   DISALLOW_NEW_EXCEPT_PLACEMENT_NEW();
   int x;
   int y;
@@ -44,11 +44,13 @@
 
 struct PLATFORM_EXPORT RasterInvalidationTracking {
   DISALLOW_NEW_EXCEPT_PLACEMENT_NEW();
-  Vector<RasterInvalidationInfo> tracked_raster_invalidations;
+  Vector<RasterInvalidationInfo> invalidations;
+
+  // The following fields are for under-raster-invalidation detection.
   sk_sp<PaintRecord> last_painted_record;
   IntRect last_interest_rect;
-  Region raster_invalidation_region_since_last_paint;
-  Vector<UnderPaintInvalidation> under_paint_invalidations;
+  Region invalidation_region_since_last_paint;
+  Vector<UnderRasterInvalidation> under_invalidations;
 
   void AsJSON(JSONObject*);
 };
@@ -57,25 +59,24 @@
 class PLATFORM_EXPORT RasterInvalidationTrackingMap {
  public:
   void AsJSON(TargetClass* key, JSONObject* json) {
-    auto it = invalidation_tracking_map_.find(key);
-    if (it != invalidation_tracking_map_.end())
+    auto it = map_.find(key);
+    if (it != map_.end())
       it->value.AsJSON(json);
   }
 
   void Remove(TargetClass* key) {
-    auto it = invalidation_tracking_map_.find(key);
-    if (it != invalidation_tracking_map_.end())
-      invalidation_tracking_map_.erase(it);
+    auto it = map_.find(key);
+    if (it != map_.end())
+      map_.erase(it);
   }
 
   RasterInvalidationTracking& Add(TargetClass* key) {
-    return invalidation_tracking_map_.insert(key, RasterInvalidationTracking())
-        .stored_value->value;
+    return map_.insert(key, RasterInvalidationTracking()).stored_value->value;
   }
 
   RasterInvalidationTracking* Find(TargetClass* key) {
-    auto it = invalidation_tracking_map_.find(key);
-    if (it == invalidation_tracking_map_.end())
+    auto it = map_.find(key);
+    if (it == map_.end())
       return nullptr;
     return &it->value;
   }
@@ -83,7 +84,7 @@
  private:
   typedef HashMap<TargetClass*, RasterInvalidationTracking>
       InvalidationTrackingMap;
-  InvalidationTrackingMap invalidation_tracking_map_;
+  InvalidationTrackingMap map_;
 };
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/platform/wtf/RefPtr.h b/third_party/WebKit/Source/platform/wtf/RefPtr.h
index 8fd8887..aa369a0e 100644
--- a/third_party/WebKit/Source/platform/wtf/RefPtr.h
+++ b/third_party/WebKit/Source/platform/wtf/RefPtr.h
@@ -56,7 +56,7 @@
   // See comments in PassRefPtr.h for an explanation of why this takes a const
   // reference.
   template <typename U>
-  RefPtr(const PassRefPtr<U>&, EnsurePtrConvertibleArgDecl(U, T));
+  RefPtr(PassRefPtr<U>&&, EnsurePtrConvertibleArgDecl(U, T));
 
   // Hash table deleted values, which are only constructed and never copied or
   // destroyed.
@@ -104,8 +104,7 @@
 
 template <typename T>
 template <typename U>
-inline RefPtr<T>::RefPtr(const PassRefPtr<U>& o,
-                         EnsurePtrConvertibleArgDefn(U, T))
+inline RefPtr<T>::RefPtr(PassRefPtr<U>&& o, EnsurePtrConvertibleArgDefn(U, T))
     : ptr_(o.LeakRef()) {}
 
 template <typename T>
diff --git a/third_party/WebKit/Source/web/WebLocalFrameImpl.cpp b/third_party/WebKit/Source/web/WebLocalFrameImpl.cpp
index 0db05d9..0328f699 100644
--- a/third_party/WebKit/Source/web/WebLocalFrameImpl.cpp
+++ b/third_party/WebKit/Source/web/WebLocalFrameImpl.cpp
@@ -311,7 +311,7 @@
     builder.Context().SetPrinting(true);
     builder.Context().BeginRecording(bounds);
     float scale = SpoolPage(builder.Context(), page_number, bounds);
-    canvas->PlaybackPaintRecord(builder.Context().EndRecording());
+    canvas->drawPicture(builder.Context().EndRecording());
     return scale;
   }
 
@@ -373,7 +373,7 @@
 
       current_height += page_size_in_pixels.Height() + 1;
     }
-    canvas->PlaybackPaintRecord(context.EndRecording());
+    canvas->drawPicture(context.EndRecording());
   }
 
  protected:
@@ -398,7 +398,8 @@
     context.ConcatCTM(transform);
     context.ClipRect(page_rect);
 
-    PaintRecordBuilder builder(bounds, &context.Canvas()->getMetaData());
+    PaintRecordBuilder builder(bounds, &context.Canvas()->getMetaData(),
+                               &context);
 
     // The local scope is so that the cache skipper is destroyed before
     // we call endRecording().
diff --git a/third_party/WebKit/Source/web/tests/VisualViewportTest.cpp b/third_party/WebKit/Source/web/tests/VisualViewportTest.cpp
index d4c6a21..a684bda1 100644
--- a/third_party/WebKit/Source/web/tests/VisualViewportTest.cpp
+++ b/third_party/WebKit/Source/web/tests/VisualViewportTest.cpp
@@ -2255,8 +2255,7 @@
   // If no invalidations occured, this will be a nullptr.
   ASSERT_TRUE(invalidation_tracking);
 
-  const auto* raster_invalidations =
-      &invalidation_tracking->tracked_raster_invalidations;
+  const auto* raster_invalidations = &invalidation_tracking->invalidations;
 
   bool root_layer_scrolling = GetParam();
 
@@ -2287,7 +2286,7 @@
                               ->GraphicsLayerBacking(document->GetLayoutView())
                               ->GetRasterInvalidationTracking();
   ASSERT_TRUE(invalidation_tracking);
-  raster_invalidations = &invalidation_tracking->tracked_raster_invalidations;
+  raster_invalidations = &invalidation_tracking->invalidations;
 
   // Once again, the entire page should have been invalidated.
   expectedHeight = root_layer_scrolling ? 480 : 1000;
@@ -2429,8 +2428,7 @@
             ->GraphicsLayerBacking()
             ->GetRasterInvalidationTracking();
     ASSERT_TRUE(invalidation_tracking);
-    const auto* raster_invalidations =
-        &invalidation_tracking->tracked_raster_invalidations;
+    const auto* raster_invalidations = &invalidation_tracking->invalidations;
     ASSERT_EQ(1u, raster_invalidations->size());
     EXPECT_EQ(IntRect(0, 0, page_width, largest_height),
               (*raster_invalidations)[0].rect);
diff --git a/third_party/WebKit/Source/web/tests/WebFrameTest.cpp b/third_party/WebKit/Source/web/tests/WebFrameTest.cpp
index 11314f5..b5779391 100644
--- a/third_party/WebKit/Source/web/tests/WebFrameTest.cpp
+++ b/third_party/WebKit/Source/web/tests/WebFrameTest.cpp
@@ -10960,8 +10960,7 @@
           ->GraphicsLayerBacking()
           ->GetRasterInvalidationTracking();
   ASSERT_TRUE(invalidation_tracking);
-  const auto* raster_invalidations =
-      &invalidation_tracking->tracked_raster_invalidations;
+  const auto* raster_invalidations = &invalidation_tracking->invalidations;
 
   // The newly revealed content at the bottom of the screen should have been
   // invalidated. There are additional invalidations for the position: fixed
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/base.py b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/base.py
index 8b60c528..bd16f41 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/base.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/base.py
@@ -357,7 +357,8 @@
         def error_handler(script_error):
             local_error.exit_code = script_error.exit_code
 
-        _log.warn('DISPLAY = %s', self.host.environ.get('DISPLAY', ''))
+        if self.host.platform.is_linux():
+            _log.debug('DISPLAY = %s', self.host.environ.get('DISPLAY', ''))
         output = self._executive.run_command(cmd, error_handler=error_handler)
         if local_error.exit_code:
             _log.error('System dependencies check failed.')
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/linux.py b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/linux.py
index f420b69..b61674b 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/linux.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/linux.py
@@ -116,7 +116,7 @@
 
     def clean_up_test_run(self):
         super(LinuxPort, self).clean_up_test_run()
-        self._stop_xvfb()
+        self._stop_xvfb(save_logs=False)
         self._clean_up_dummy_home_dir()
 
     #
@@ -190,13 +190,13 @@
             exit_code = self.host.executive.run_command(
                 ['xdpyinfo'], return_exit_code=True)
             if exit_code == 0:
-                _log.info('Successfully started Xvfb with display "%s".', display)
+                _log.debug('Successfully started Xvfb with display "%s".', display)
                 return
             _log.warn('xdpyinfo check failed with exit code %s while starting Xvfb on "%s".', exit_code, display)
             self.host.sleep(0.1)
 
         retcode = self._xvfb_process.poll()
-        self._stop_xvfb()
+        self._stop_xvfb(save_logs=True)
         _log.critical('Failed to start Xvfb on display "%s" (xvfb retcode: %r).', display, retcode)
 
     def _find_display(self):
@@ -210,7 +210,7 @@
                 return display
         return None
 
-    def _stop_xvfb(self):
+    def _stop_xvfb(self, save_logs):
         if self._original_display:
             self.host.environ['DISPLAY'] = self._original_display
         if self._xvfb_stdout:
@@ -221,11 +221,11 @@
             _log.debug('Killing Xvfb process pid %d.', self._xvfb_process.pid)
             self._xvfb_process.kill()
             self._xvfb_process.wait()
-        if self._xvfb_stdout and self.host.filesystem.exists(self._xvfb_stdout.name):
+        if save_logs and self._xvfb_stdout and self.host.filesystem.exists(self._xvfb_stdout.name):
             for line in self.host.filesystem.read_text_file(self._xvfb_stdout.name).splitlines():
                 _log.warn('Xvfb stdout:  %s', line)
             self.host.filesystem.remove(self._xvfb_stdout.name)
-        if self._xvfb_stderr and self.host.filesystem.exists(self._xvfb_stderr.name):
+        if save_logs and self._xvfb_stderr and self.host.filesystem.exists(self._xvfb_stderr.name):
             for line in self.host.filesystem.read_text_file(self._xvfb_stderr.name).splitlines():
                 _log.warn('Xvfb stderr:  %s', line)
             self.host.filesystem.remove(self._xvfb_stderr.name)
diff --git a/third_party/WebKit/public/platform/WebMediaPlayer.h b/third_party/WebKit/public/platform/WebMediaPlayer.h
index 387375e8..aa08930 100644
--- a/third_party/WebKit/public/platform/WebMediaPlayer.h
+++ b/third_party/WebKit/public/platform/WebMediaPlayer.h
@@ -180,34 +180,22 @@
 
   virtual void Paint(WebCanvas*, const WebRect&, cc::PaintFlags&) = 0;
 
-  // TODO(kbr): remove non-|target| version. crbug.com/349871
-  //
   // Do a GPU-GPU texture copy of the current video frame to |texture|,
   // reallocating |texture| at the appropriate size with given internal
   // format, format, and type if necessary. If the copy is impossible
   // or fails, it returns false.
   virtual bool CopyVideoTextureToPlatformTexture(gpu::gles2::GLES2Interface*,
-                                                 unsigned texture,
-                                                 unsigned internal_format,
-                                                 unsigned format,
-                                                 unsigned type,
-                                                 bool premultiply_alpha,
-                                                 bool flip_y) {
-    return false;
-  }
-
-  // Do a GPU-GPU textures copy. If the copy is impossible or fails, it returns
-  // false.
-  virtual bool CopyVideoTextureToPlatformTexture(gpu::gles2::GLES2Interface*,
                                                  unsigned target,
                                                  unsigned texture,
                                                  unsigned internal_format,
+                                                 unsigned format,
                                                  unsigned type,
                                                  int level,
                                                  bool premultiply_alpha,
                                                  bool flip_y) {
     return false;
   }
+
   // Copy sub video frame texture to |texture|. If the copy is impossible or
   // fails, it returns false.
   virtual bool CopyVideoSubTextureToPlatformTexture(gpu::gles2::GLES2Interface*,
diff --git a/tools/android/eclipse/.classpath b/tools/android/eclipse/.classpath
index 43248a3..17a0858 100644
--- a/tools/android/eclipse/.classpath
+++ b/tools/android/eclipse/.classpath
@@ -25,6 +25,7 @@
     <classpathentry kind="src" path="android_webview/tools/system_webview_shell/layout_tests/src"/>
     <classpathentry kind="src" path="base/android/java/src"/>
     <classpathentry kind="src" path="base/android/javatests/src"/>
+    <classpathentry kind="src" path="base/android/junit/src"/>
     <classpathentry kind="src" path="base/test/android/javatests/src"/>
     <classpathentry kind="src" path="base/test/android/junit/src"/>
     <classpathentry kind="src" path="chrome/android/java/src"/>
diff --git a/tools/binary_size/libsupersize/archive.py b/tools/binary_size/libsupersize/archive.py
index a32d573..f47ab14 100644
--- a/tools/binary_size/libsupersize/archive.py
+++ b/tools/binary_size/libsupersize/archive.py
@@ -382,12 +382,14 @@
     timestamp_obj = datetime.datetime.utcfromtimestamp(os.path.getmtime(
         elf_path))
     timestamp = calendar.timegm(timestamp_obj.timetuple())
+    relative_tool_prefix = paths.ToSrcRootRelative(tool_prefix)
 
     metadata = {
         models.METADATA_GIT_REVISION: git_rev,
         models.METADATA_ELF_ARCHITECTURE: architecture,
         models.METADATA_ELF_MTIME: timestamp,
         models.METADATA_ELF_BUILD_ID: build_id,
+        models.METADATA_TOOL_PREFIX: relative_tool_prefix,
     }
 
     if output_directory:
diff --git a/tools/binary_size/libsupersize/console.py b/tools/binary_size/libsupersize/console.py
index f019564..1e87f44 100644
--- a/tools/binary_size/libsupersize/console.py
+++ b/tools/binary_size/libsupersize/console.py
@@ -66,7 +66,7 @@
 class _Session(object):
   _readline_initialized = False
 
-  def __init__(self, size_infos, lazy_paths):
+  def __init__(self, size_infos, size_paths, lazy_paths):
     self._variables = {
         'Print': self._PrintFunc,
         'Diff': self._DiffFunc,
@@ -77,6 +77,8 @@
     }
     self._lazy_paths = lazy_paths
     self._size_infos = size_infos
+    self._size_paths = size_paths
+    self._disassemble_prefix_len = None
 
     if len(size_infos) == 1:
       self._variables['size_info'] = size_infos[0]
@@ -119,23 +121,71 @@
     lines = describe.GenerateLines(obj, verbose=verbose, recursive=recursive)
     _WriteToStream(lines, use_pager=use_pager, to_file=to_file)
 
-  def _ElfPathForSymbol(self, symbol):
+  def _ElfPathAndToolPrefixForSymbol(self, symbol, elf_path, tool_prefix):
     size_info = None
-    for size_info in self._size_infos:
+    size_path = None
+    for size_info, size_path in zip(self._size_infos, self._size_paths):
       if symbol in size_info.symbols:
         break
     else:
-      assert False, 'Symbol does not belong to a size_info.'
+      # If symbols is from a diff(), use its address+name to find it.
+      for size_info, size_path in zip(self._size_infos, self._size_paths):
+        matched = size_info.symbols.WhereAddressInRange(symbol.address)
+        # Use last matched symbol to skip over padding-only symbols.
+        if len(matched) > 0 and matched[-1].full_name == symbol.full_name:
+          symbol = matched[-1]
+          break
+      else:
+        assert False, 'Symbol does not belong to a size_info.'
 
-    filename = size_info.metadata.get(models.METADATA_ELF_FILENAME)
-    output_dir = self._lazy_paths.output_directory or ''
-    path = os.path.normpath(os.path.join(output_dir, filename))
+    orig_tool_prefix = size_info.metadata.get(models.METADATA_TOOL_PREFIX)
+    if orig_tool_prefix:
+      orig_tool_prefix = paths.FromSrcRootRelative(orig_tool_prefix)
+      if os.path.exists(orig_tool_prefix + 'objdump'):
+        tool_prefix = orig_tool_prefix
 
-    found_build_id = archive.BuildIdFromElf(path, self._lazy_paths.tool_prefix)
+    # TODO(agrieve): Would be even better to use objdump --info to check that
+    #     the toolchain is for the correct architecture.
+    assert tool_prefix is not None, (
+        'Could not determine --tool-prefix. Possible fixes include setting '
+        '--tool-prefix, or setting --output-directory')
+
+    if elf_path is None:
+      filename = size_info.metadata.get(models.METADATA_ELF_FILENAME)
+      output_dir = self._lazy_paths.output_directory
+      size_path = self._size_paths[self._size_infos.index(size_info)]
+      if output_dir:
+        # Local build: File is located in output directory.
+        path = os.path.normpath(os.path.join(output_dir, filename))
+      if not output_dir or not os.path.exists(path):
+        # Downloaded build: File is located beside .size file.
+        path = os.path.normpath(os.path.join(
+            os.path.dirname(size_path), os.path.basename(filename)))
+
+      assert os.path.exists(path), (
+          'Could locate ELF file. If binary was built locally, ensure '
+          '--output-directory is set. If output directory is unavailable, '
+          'ensure {} is located beside {}, or pass its path explicitly using '
+          'elf_path=').format(os.path.basename(filename), size_path)
+
+    found_build_id = archive.BuildIdFromElf(path, tool_prefix)
     expected_build_id = size_info.metadata.get(models.METADATA_ELF_BUILD_ID)
     assert found_build_id == expected_build_id, (
         'Build ID does not match for %s' % path)
-    return path
+    return path, tool_prefix
+
+  def _DetectDisassemblePrefixLen(self, args):
+    # Look for a line that looks like:
+    # /usr/{snip}/src/out/Release/../../net/quic/core/quic_time.h:100
+    output = subprocess.check_output(args)
+    for line in output.splitlines():
+      if line and line[0] == os.path.sep and line[-1].isdigit():
+        release_idx = line.find('Release')
+        if release_idx == -1:
+          break
+        return line.count(os.path.sep, 0, release_idx)
+    logging.warning('Found no source paths in objdump output.')
+    return None
 
   def _DisassembleFunc(self, symbol, elf_path=None, use_pager=None,
                        to_file=None):
@@ -147,13 +197,34 @@
           when auto-detection fails.
     """
     assert symbol.address and symbol.section_name == '.text'
-    if not elf_path:
-      elf_path = self._ElfPathForSymbol(symbol)
+
     tool_prefix = self._lazy_paths.tool_prefix
+    if not elf_path:
+      elf_path, tool_prefix = self._ElfPathAndToolPrefixForSymbol(
+          symbol, elf_path, tool_prefix)
+
     args = [tool_prefix + 'objdump', '--disassemble', '--source',
             '--line-numbers', '--demangle',
             '--start-address=0x%x' % symbol.address,
             '--stop-address=0x%x' % symbol.end_address, elf_path]
+    if self._disassemble_prefix_len is None:
+      prefix_len = self._DetectDisassemblePrefixLen(args)
+      if prefix_len is not None:
+        self._disassemble_prefix_len = prefix_len
+
+    if self._disassemble_prefix_len is not None:
+      output_directory = self._lazy_paths.output_directory
+      # Only matters for non-generated paths, so be lenient here.
+      if output_directory is None:
+        output_directory = os.path.join(paths.SRC_ROOT, 'out', 'Release')
+        if not os.path.exists(output_directory):
+          os.makedirs(output_directory)
+
+      args += [
+          '--prefix-strip', str(self._disassemble_prefix_len),
+          '--prefix', os.path.normpath(os.path.relpath(output_directory))
+      ]
+
     proc = subprocess.Popen(args, stdout=subprocess.PIPE)
     lines = itertools.chain(('Showing disassembly for %r' % symbol,
                              'Command: %s' % ' '.join(args)),
@@ -174,7 +245,7 @@
         '# Show two levels of .text, grouped by first two subdirectories',
         'text_syms = size_info.symbols.WhereInSection("t")',
         'by_path = text_syms.GroupedByPath(depth=2)',
-        'Print(by_path.WhereBiggerThan(1024))',
+        'Print(by_path.WherePssBiggerThan(1024))',
         '',
         '# Show all non-vtable generated symbols',
         'generated_syms = size_info.symbols.WhereGeneratedByToolchain()',
@@ -276,7 +347,7 @@
   lazy_paths = paths.LazyPaths(tool_prefix=args.tool_prefix,
                                output_directory=args.output_directory,
                                any_path_within_output_directory=args.inputs[0])
-  session = _Session(size_infos, lazy_paths)
+  session = _Session(size_infos, args.inputs, lazy_paths)
 
   if args.query:
     logging.info('Running query from command-line.')
diff --git a/tools/binary_size/libsupersize/helpers.py b/tools/binary_size/libsupersize/helpers.py
deleted file mode 100644
index bddcd764..0000000
--- a/tools/binary_size/libsupersize/helpers.py
+++ /dev/null
@@ -1,11 +0,0 @@
-# Copyright 2017 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-"""Utility methods."""
-
-import os
-
-
-SRC_ROOT = os.path.dirname(
-    os.path.dirname(os.path.dirname(os.path.dirname(__file__))))
diff --git a/tools/binary_size/libsupersize/html_report.py b/tools/binary_size/libsupersize/html_report.py
index d4e51579..d5073bdc 100644
--- a/tools/binary_size/libsupersize/html_report.py
+++ b/tools/binary_size/libsupersize/html_report.py
@@ -12,7 +12,7 @@
 import sys
 
 import archive
-import helpers
+import paths
 
 
 # Node dictionary keys. These are output in json read by the webapp so
@@ -154,7 +154,7 @@
   d3_out = os.path.join(dest_dir, 'd3')
   if not os.path.exists(d3_out):
     os.makedirs(d3_out, 0755)
-  d3_src = os.path.join(helpers.SRC_ROOT, 'third_party', 'd3', 'src')
+  d3_src = os.path.join(paths.SRC_ROOT, 'third_party', 'd3', 'src')
   template_src = os.path.join(os.path.dirname(__file__), 'template')
   shutil.copy(os.path.join(d3_src, 'LICENSE'), d3_out)
   shutil.copy(os.path.join(d3_src, 'd3.js'), d3_out)
@@ -184,7 +184,7 @@
   symbols = size_info.symbols
   if not args.include_bss:
     symbols = symbols.WhereInSection('b').Inverted()
-  symbols = symbols.WhereBiggerThan(0)
+  symbols = symbols.WherePssBiggerThan(0)
 
   # Copy report boilerplate into output directory. This also proves that the
   # output directory is safe for writing, so there should be no problems writing
diff --git a/tools/binary_size/libsupersize/integration_test.py b/tools/binary_size/libsupersize/integration_test.py
index 9114e10a..3a4302b 100755
--- a/tools/binary_size/libsupersize/integration_test.py
+++ b/tools/binary_size/libsupersize/integration_test.py
@@ -86,6 +86,7 @@
 
 
 class IntegrationTest(unittest.TestCase):
+  maxDiff = None  # Don't trucate diffs in errors.
   cached_size_info = [None, None, None]
 
   def _CloneSizeInfo(self, use_output_directory=True, use_elf=True):
diff --git a/tools/binary_size/libsupersize/models.py b/tools/binary_size/libsupersize/models.py
index 31d01e59..88716da 100644
--- a/tools/binary_size/libsupersize/models.py
+++ b/tools/binary_size/libsupersize/models.py
@@ -42,6 +42,7 @@
 METADATA_ELF_MTIME = 'elf_mtime'  # int timestamp in utc.
 METADATA_ELF_BUILD_ID = 'elf_build_id'
 METADATA_GN_ARGS = 'gn_args'
+METADATA_TOOL_PREFIX = 'tool_prefix'  # Path relative to SRC_ROOT.
 
 
 SECTION_TO_SECTION_NAME = {
@@ -456,9 +457,12 @@
                                    filtered_symbols=filtered_and_kept[0],
                                    section_name=self.section_name)
 
-  def WhereBiggerThan(self, min_size):
+  def WhereSizeBiggerThan(self, min_size):
     return self.Filter(lambda s: s.size >= min_size)
 
+  def WherePssBiggerThan(self, min_pss):
+    return self.Filter(lambda s: s.pss >= min_pss)
+
   def WhereInSection(self, section):
     if len(section) == 1:
       ret = self.Filter(lambda s: s.section == section)
diff --git a/tools/binary_size/libsupersize/paths.py b/tools/binary_size/libsupersize/paths.py
index 53acb740..fb8eed645 100644
--- a/tools/binary_size/libsupersize/paths.py
+++ b/tools/binary_size/libsupersize/paths.py
@@ -11,6 +11,9 @@
 _STATUS_DETECTED = 1
 _STATUS_VERIFIED = 2
 
+SRC_ROOT = os.path.dirname(
+    os.path.dirname(os.path.dirname(os.path.dirname(__file__))))
+
 
 class LazyPaths(object):
   def __init__(self, tool_prefix=None, output_directory=None,
@@ -87,6 +90,29 @@
       if os.path.exists(build_vars_path):
         with open(build_vars_path) as f:
           build_vars = dict(l.rstrip().split('=', 1) for l in f if '=' in l)
-        return os.path.normpath(
-            os.path.join(output_directory, build_vars['android_tool_prefix']))
+        tool_prefix = build_vars['android_tool_prefix']
+        ret = os.path.normpath(os.path.join(output_directory, tool_prefix))
+        # Need to maintain a trailing /.
+        if tool_prefix.endswith(os.path.sep):
+          ret += os.path.sep
+        return ret
+    from_path = distutils.spawn.find_executable('c++filt')
+    if from_path:
+      return from_path[:-7]
     return None
+
+
+def FromSrcRootRelative(path):
+  ret = os.path.relpath(os.path.join(SRC_ROOT, path))
+  # Need to maintain a trailing /.
+  if path.endswith(os.path.sep):
+    ret += os.path.sep
+  return ret
+
+
+def ToSrcRootRelative(path):
+  ret = os.path.relpath(path, SRC_ROOT)
+  # Need to maintain a trailing /.
+  if path.endswith(os.path.sep):
+    ret += os.path.sep
+  return ret
diff --git a/tools/binary_size/libsupersize/testdata/Archive_Elf.golden b/tools/binary_size/libsupersize/testdata/Archive_Elf.golden
index 0faa42d..c2fd8d5 100644
--- a/tools/binary_size/libsupersize/testdata/Archive_Elf.golden
+++ b/tools/binary_size/libsupersize/testdata/Archive_Elf.golden
@@ -5,6 +5,7 @@
 git_revision=abc123
 gn_args=var1=true var2="foo"
 map_file_name=../test.map
+tool_prefix=tools/binary_size/libsupersize/testdata/mock_toolchain/
 Section r: has 100.0% of 5927652 bytes accounted for from 9 symbols. 0 bytes are unaccounted for.
 * Padding accounts for 11 bytes (0.0%)
 * 4 placeholders (symbols that start with **) account for 5927509 bytes (100.0%)
diff --git a/tools/binary_size/libsupersize/testdata/Console.golden b/tools/binary_size/libsupersize/testdata/Console.golden
index 5be0f769a..881e6d9b 100644
--- a/tools/binary_size/libsupersize/testdata/Console.golden
+++ b/tools/binary_size/libsupersize/testdata/Console.golden
@@ -4,7 +4,7 @@
 SizeInfo: Clustered, metadata, raw_symbols, section_sizes, symbols
 Symbol: FlagsString, IsBss, IsGeneratedByToolchain, IsGroup, address, aliases, end_address, flags, full_name, generated_source, is_anonymous, name, num_aliases, object_path, padding, pss, pss_without_padding, section, section_name, size, size_without_padding, source_path, template_name
 
-SymbolGroup (extends Symbol): Clustered, CountUniqueSymbols, Filter, GroupedBy, GroupedByName, GroupedByPath, GroupedBySectionName, Inverted, IterLeafSymbols, IterUniqueSymbols, Sorted, SortedByAddress, SortedByCount, SortedByName, WhereAddressInRange, WhereBiggerThan, WhereFullNameMatches, WhereGeneratedByToolchain, WhereHasAnyAttribution, WhereHasPath, WhereInSection, WhereIsTemplate, WhereMatches, WhereNameMatches, WhereObjectPathMatches, WherePathMatches, WhereSourceIsGenerated, WhereSourcePathMatches, WhereTemplateNameMatches, is_sorted
+SymbolGroup (extends Symbol): Clustered, CountUniqueSymbols, Filter, GroupedBy, GroupedByName, GroupedByPath, GroupedBySectionName, Inverted, IterLeafSymbols, IterUniqueSymbols, Sorted, SortedByAddress, SortedByCount, SortedByName, WhereAddressInRange, WhereFullNameMatches, WhereGeneratedByToolchain, WhereHasAnyAttribution, WhereHasPath, WhereInSection, WhereIsTemplate, WhereMatches, WhereNameMatches, WhereObjectPathMatches, WherePathMatches, WherePssBiggerThan, WhereSizeBiggerThan, WhereSourceIsGenerated, WhereSourcePathMatches, WhereTemplateNameMatches, is_sorted
 
 SymbolDiff (extends SymbolGroup): IsAdded, IsRemoved, IsSimilar, WhereNotUnchanged, added_count, changed_count, removed_count, unchanged_count
 
@@ -23,7 +23,7 @@
 # Show two levels of .text, grouped by first two subdirectories
 text_syms = size_info.symbols.WhereInSection("t")
 by_path = text_syms.GroupedByPath(depth=2)
-Print(by_path.WhereBiggerThan(1024))
+Print(by_path.WherePssBiggerThan(1024))
 
 # Show all non-vtable generated symbols
 generated_syms = size_info.symbols.WhereGeneratedByToolchain()
@@ -54,6 +54,7 @@
     git_revision=abc123
     gn_args=var1=true var2="foo"
     map_file_name=../test.map
+    tool_prefix=tools/binary_size/libsupersize/testdata/mock_toolchain/
 
 Section Sizes (Total=41.8mb (43785380 bytes)):
     .bss: 1.24mb (1300456 bytes) (not included in totals)
diff --git a/tools/binary_size/libsupersize/testdata/Diff_NullDiff.golden b/tools/binary_size/libsupersize/testdata/Diff_NullDiff.golden
index 8c04fa7..13d157b3 100644
--- a/tools/binary_size/libsupersize/testdata/Diff_NullDiff.golden
+++ b/tools/binary_size/libsupersize/testdata/Diff_NullDiff.golden
@@ -6,6 +6,7 @@
     git_revision=abc123
     gn_args=var1=true var2="foo"
     map_file_name=../test.map
+    tool_prefix=tools/binary_size/libsupersize/testdata/mock_toolchain/
 Old Metadata:
 New Metadata:
 
diff --git a/tools/binary_size/libsupersize/testdata/FullDescription.golden b/tools/binary_size/libsupersize/testdata/FullDescription.golden
index f1b1a14..5f92eb1 100644
--- a/tools/binary_size/libsupersize/testdata/FullDescription.golden
+++ b/tools/binary_size/libsupersize/testdata/FullDescription.golden
@@ -6,6 +6,7 @@
     git_revision=abc123
     gn_args=var1=true var2="foo"
     map_file_name=../test.map
+    tool_prefix=tools/binary_size/libsupersize/testdata/mock_toolchain/
 
 Section Sizes (Total=41.8mb (43785380 bytes)):
     .bss: 1.24mb (1300456 bytes) (not included in totals)
diff --git a/tools/mb/mb_config.pyl b/tools/mb/mb_config.pyl
index 1c8af73e..57e79d71 100644
--- a/tools/mb/mb_config.pyl
+++ b/tools/mb/mb_config.pyl
@@ -667,6 +667,10 @@
         '1': 'official_optimize_chrome_pgo_phase_1_x86',
         '2': 'official_optimize_chrome_pgo_phase_2_x86',
       },
+      'win_pgo_x64': {
+        '1': 'official_optimize_chrome_pgo_phase_1',
+        '2': 'official_optimize_chrome_pgo_phase_2',
+      },
       'win_upload_clang': 'release_bot',
       'win_chrome_official': 'official_goma_x86',
     },
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index 8f1ab9bf..18e27ef 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -15760,6 +15760,22 @@
   <int value="1" label="Space key"/>
 </enum>
 
+<enum name="FileManagerRootType" type="int">
+  <int value="0" label="DOWNLOADS"/>
+  <int value="1" label="ARCHIVE"/>
+  <int value="2" label="REMOVABLE"/>
+  <int value="3" label="DRIVE"/>
+  <int value="4" label="TEAM_DRIVES_GRAND_ROOT"/>
+  <int value="5" label="TEAM_DRIVE"/>
+  <int value="6" label="MTP"/>
+  <int value="7" label="PROVIDED"/>
+  <int value="8" label="DRIVE_OTHER"/>
+  <int value="9" label="DRIVE_OFFLINE"/>
+  <int value="10" label="DRIVE_SHARED_WITH_ME"/>
+  <int value="11" label="DRIVE_RECENT"/>
+  <int value="12" label="MEDIA_VIEW"/>
+</enum>
+
 <enum name="FileManagerVolumeType" type="int">
   <int value="0" label="Google Drive"/>
   <int value="1" label="Download Folder"/>
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index 06a009a..501b53f 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -21017,6 +21017,14 @@
   <summary>Records the source that requested showing the feedback app.</summary>
 </histogram>
 
+<histogram name="FileBrowser.ChangeDirectory" enum="FileManagerRootType">
+  <owner>yamaguchi@chromium.com</owner>
+  <summary>
+    Chrome OS File Browser: Counts the number of directory-changed events,
+    bucketed by the RootType of the directory newly displayed.
+  </summary>
+</histogram>
+
 <histogram name="FileBrowser.CloudImport.UserAction"
     enum="CloudImportUserAction">
   <owner>smckay@google.com</owner>
@@ -71417,6 +71425,11 @@
   </summary>
 </histogram>
 
+<histogram base="true" name="Storage.Blob.SizeEvictedToDiskInKB" units="KB">
+  <owner>ssid@chromium.org</owner>
+  <summary>Records the total size of in-memory blobs evicted to disk.</summary>
+</histogram>
+
 <histogram name="Storage.Blob.StorageSizeAfterAppend" units="KB">
   <owner>dmurph@chromium.org</owner>
   <summary>
@@ -91895,6 +91908,18 @@
   <affected-histogram name="Storage.BlobItemSize.BlobSlice"/>
 </histogram_suffixes>
 
+<histogram_suffixes name="Storage.BlobEvictReason" separator=".">
+  <suffix name="OnMemoryPressure"
+      label="Eviction was triggered because of memory pressure signal."/>
+  <suffix name="SizeExceededMaxDiskSpace"
+      label="Eviction was triggered because the total size exceeded maximum
+             available disk space"/>
+  <suffix name="SizeExceededInMemoryLimit"
+      label="Eviction was triggered because the total size exceeded maximum
+             in memory size allwed"/>
+  <affected-histogram name="Storage.Blob.SizeEvictedToDiskInKB"/>
+</histogram_suffixes>
+
 <histogram_suffixes name="StunPingInternal" separator=".">
   <suffix name="0ms" label="0ms between requests"/>
   <suffix name="5ms" label="5ms between requests"/>
diff --git a/ui/file_manager/file_manager/foreground/js/compiled_resources.gyp b/ui/file_manager/file_manager/foreground/js/compiled_resources.gyp
index cabb7fa..3634861 100644
--- a/ui/file_manager/file_manager/foreground/js/compiled_resources.gyp
+++ b/ui/file_manager/file_manager/foreground/js/compiled_resources.gyp
@@ -120,6 +120,7 @@
           './metadata_update_controller.js',
           './naming_controller.js',
           './navigation_list_model.js',
+          './navigation_uma.js',
           './progress_center_item_group.js',
           './quick_view_controller.js',
           './quick_view_model.js',
diff --git a/ui/file_manager/file_manager/foreground/js/compiled_resources2.gyp b/ui/file_manager/file_manager/foreground/js/compiled_resources2.gyp
index fd24079..33ec35c5 100644
--- a/ui/file_manager/file_manager/foreground/js/compiled_resources2.gyp
+++ b/ui/file_manager/file_manager/foreground/js/compiled_resources2.gyp
@@ -105,6 +105,14 @@
       'includes': ['../../../compile_js2.gypi'],
     },
     {
+      'target_name': 'navigation_uma',
+      'dependencies': [
+        'dialog_type',
+        'volume_manager_wrapper',
+      ],
+      'includes': ['../../../compile_js2.gypi'],
+    },
+    {
       'target_name': 'directory_tree_naming_controller',
       'dependencies': [
         '../../common/js/compiled_resources2.gyp:util',
diff --git a/ui/file_manager/file_manager/foreground/js/file_manager.js b/ui/file_manager/file_manager/foreground/js/file_manager.js
index c4635da0..926b5644 100644
--- a/ui/file_manager/file_manager/foreground/js/file_manager.js
+++ b/ui/file_manager/file_manager/foreground/js/file_manager.js
@@ -278,6 +278,13 @@
    */
   this.quickViewController_ = null;
 
+  /**
+   * Records histograms of directory-changed event.
+   * @type {NavigationUma}
+   * @private
+   */
+  this.navigationUma_ = null;
+
   // --------------------------------------------------------------------------
   // DOM elements.
 
@@ -514,6 +521,13 @@
       listBeingUpdated = null;
     });
 
+    this.directoryModel_.addEventListener(
+        'directory-changed',
+        /** @param {!Event} event */
+        function(event) {
+          this.navigationUma_.onDirectoryChanged(event.newDirEntry);
+        }.bind(this));
+
     this.initCommands_();
 
     assert(this.directoryModel_);
@@ -1117,6 +1131,7 @@
     var addNewServicesVisible =
         this.dialogType === DialogType.FULL_PAGE &&
         !chrome.extension.inIncognitoContext;
+    this.navigationUma_ = new NavigationUma(assert(this.volumeManager_));
     DirectoryTree.decorate(directoryTree,
                            assert(this.directoryModel_),
                            assert(this.volumeManager_),
diff --git a/ui/file_manager/file_manager/foreground/js/main_scripts.js b/ui/file_manager/file_manager/foreground/js/main_scripts.js
index 057c88e..747437e9 100644
--- a/ui/file_manager/file_manager/foreground/js/main_scripts.js
+++ b/ui/file_manager/file_manager/foreground/js/main_scripts.js
@@ -138,6 +138,7 @@
 // <include src="metadata_update_controller.js">
 // <include src="naming_controller.js">
 // <include src="navigation_list_model.js">
+// <include src="navigation_uma.js">
 // <include src="progress_center_item_group.js">
 // <include src="quick_view_controller.js">
 // <include src="quick_view_model.js">
diff --git a/ui/file_manager/file_manager/foreground/js/navigation_uma.js b/ui/file_manager/file_manager/foreground/js/navigation_uma.js
new file mode 100644
index 0000000..4b20782
--- /dev/null
+++ b/ui/file_manager/file_manager/foreground/js/navigation_uma.js
@@ -0,0 +1,64 @@
+// 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.
+
+/**
+ * UMA exporter for navigation in the Files app.
+ *
+ * @param {!VolumeManagerWrapper} volumeManager
+ *
+ * @constructor
+ */
+function NavigationUma(volumeManager) {
+  /**
+   * @type {!VolumeManagerWrapper}
+   * @private
+   */
+  this.volumeManager_ = volumeManager;
+}
+
+/**
+ * Keep the order of this in sync with FileManagerRootType in
+ * tools/metrics/histograms/histograms.xml.
+ *
+ * @type {!Array<VolumeManagerCommon.RootType>}
+ * @const
+ */
+NavigationUma.RootType = [
+  VolumeManagerCommon.RootType.DOWNLOADS,
+  VolumeManagerCommon.RootType.ARCHIVE,
+  VolumeManagerCommon.RootType.REMOVABLE,
+  VolumeManagerCommon.RootType.DRIVE,
+  VolumeManagerCommon.RootType.TEAM_DRIVES_GRAND_ROOT,
+  VolumeManagerCommon.RootType.TEAM_DRIVE,
+  VolumeManagerCommon.RootType.MTP,
+  VolumeManagerCommon.RootType.PROVIDED,
+  VolumeManagerCommon.RootType.DRIVE_OTHER,
+  VolumeManagerCommon.RootType.DRIVE_OFFLINE,
+  VolumeManagerCommon.RootType.DRIVE_SHARED_WITH_ME,
+  VolumeManagerCommon.RootType.DRIVE_RECENT,
+  VolumeManagerCommon.RootType.MEDIA_VIEW,
+];
+
+/**
+ * Exports file type metric with the given |name|.
+ *
+ * @param {!FileEntry} entry
+ * @param {string} name The histogram name.
+ *
+ * @private
+ */
+NavigationUma.prototype.exportRootType_ = function(entry, name) {
+  var locationInfo = this.volumeManager_.getLocationInfo(entry);
+  if (locationInfo)
+    metrics.recordEnum(name, locationInfo.rootType, NavigationUma.RootType);
+};
+
+/**
+ * Exports UMA based on the entry that has became new current directory.
+ *
+ * @param {!FileEntry} entry the new directory
+ */
+NavigationUma.prototype.onDirectoryChanged = function(entry) {
+  this.exportRootType_(entry, 'FileBrowser.ChangeDirectory.RootType');
+};