diff --git a/DEPS b/DEPS
index cdd076e..d5cca170 100644
--- a/DEPS
+++ b/DEPS
@@ -43,7 +43,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
-  'v8_revision': 'd6a1568f656bfeacd8e85bdd6cddf04fea906336',
+  'v8_revision': 'b1a1553d4c8f55a0fa515f063734c372f0bfda2b',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling swarming_client
   # and whatever else without interference from each other.
@@ -51,7 +51,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling ANGLE
   # and whatever else without interference from each other.
-  'angle_revision': '5fc4e56dfa3fade0b683a7b42e691137bda5fed0',
+  'angle_revision': 'c8c99a0a5d73a6494aebce463aef1eecca1304a9',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling build tools
   # and whatever else without interference from each other.
@@ -187,7 +187,7 @@
    Var('chromium_git') + '/chromium/third_party/ffmpeg.git' + '@' + 'd1e9c4bbd95af9a089d224edf87fd0c3f33ece96',
 
   'src/third_party/libjingle/source/talk':
-    Var('chromium_git') + '/external/webrtc/trunk/talk.git' + '@' + '1c16da383ac3d7a51088722fab024533efc9dbce', # commit position 11275
+    Var('chromium_git') + '/external/webrtc/trunk/talk.git' + '@' + 'd9abcae5ed8678a1b32bb8dad1b84eba82546910', # commit position 11290
 
   'src/third_party/usrsctp/usrsctplib':
     Var('chromium_git') + '/external/github.com/sctplab/usrsctp' + '@' + 'c60ec8b35c3fe6027d7a3faae89d1c8d7dd3ce98',
@@ -211,7 +211,7 @@
    Var('chromium_git') + '/native_client/src/third_party/scons-2.0.1.git' + '@' + '1c1550e17fc26355d08627fbdec13d8291227067',
 
   'src/third_party/webrtc':
-    Var('chromium_git') + '/external/webrtc/trunk/webrtc.git' + '@' + 'ef78a80a92b3bfe0cb3e720b15174759a9d3d5e0', # commit position 11275
+    Var('chromium_git') + '/external/webrtc/trunk/webrtc.git' + '@' + '8d5f2987a2d68d2b2ce30155c6bbcf8fb217692a', # commit position 11288
 
   'src/third_party/openmax_dl':
     Var('chromium_git') + '/external/webrtc/deps/third_party/openmax.git' + '@' +  Var('openmax_dl_revision'),
diff --git a/ash/ash.gyp b/ash/ash.gyp
index f87be98..1df3b4d 100644
--- a/ash/ash.gyp
+++ b/ash/ash.gyp
@@ -147,8 +147,6 @@
       'gpu_support_stub.h',
       'high_contrast/high_contrast_controller.cc',
       'high_contrast/high_contrast_controller.h',
-      'host/ash_remote_window_tree_host_win.cc',
-      'host/ash_remote_window_tree_host_win.h',
       'host/ash_window_tree_host.cc',
       'host/ash_window_tree_host.h',
       'host/ash_window_tree_host_init_params.cc',
diff --git a/ash/ash_unittests.isolate b/ash/ash_unittests.isolate
index a210ff8..89ab132b 100644
--- a/ash/ash_unittests.isolate
+++ b/ash/ash_unittests.isolate
@@ -26,7 +26,7 @@
         ],
       },
     }],
-    ['OS=="win" or chromeos==1', {
+    ['chromeos==1', {
       'variables': {
         'files': [
           '../testing/test_env.py',
@@ -52,20 +52,6 @@
         ],
       },
     }],
-    ['OS=="win"', {
-      'variables': {
-        'files': [
-          '<(PRODUCT_DIR)/osmesa.dll',
-        ],
-      },
-    }],
-    ['OS=="win" and (fastbuild==0 or fastbuild==1)', {
-      'variables': {
-        'files': [
-          '<(PRODUCT_DIR)/ash_unittests.exe.pdb',
-        ],
-      },
-    }],
   ],
   'includes': [
     '../base/base.isolate',
diff --git a/ash/host/ash_remote_window_tree_host_win.cc b/ash/host/ash_remote_window_tree_host_win.cc
deleted file mode 100644
index f3191b5e..0000000
--- a/ash/host/ash_remote_window_tree_host_win.cc
+++ /dev/null
@@ -1,71 +0,0 @@
-// Copyright 2014 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 "ash/host/ash_remote_window_tree_host_win.h"
-
-#include "ash/host/root_window_transformer.h"
-#include "ash/ime/input_method_event_handler.h"
-#include "ui/events/event_processor.h"
-#include "ui/gfx/geometry/insets.h"
-#include "ui/gfx/transform.h"
-
-namespace ash {
-
-AshRemoteWindowTreeHostWin::AshRemoteWindowTreeHostWin(HWND remote_hwnd)
-    : aura::RemoteWindowTreeHostWin(),
-      transformer_helper_(this) {
-  SetRemoteWindowHandle(remote_hwnd);
-  transformer_helper_.Init();
-}
-
-AshRemoteWindowTreeHostWin::~AshRemoteWindowTreeHostWin() {}
-
-void AshRemoteWindowTreeHostWin::ToggleFullScreen() {}
-
-bool AshRemoteWindowTreeHostWin::ConfineCursorToRootWindow() { return false; }
-
-void AshRemoteWindowTreeHostWin::UnConfineCursor() {}
-
-void AshRemoteWindowTreeHostWin::SetRootWindowTransformer(
-    scoped_ptr<RootWindowTransformer> transformer) {
-  transformer_helper_.SetRootWindowTransformer(transformer.Pass());
-}
-
-gfx::Insets AshRemoteWindowTreeHostWin::GetHostInsets() const {
-  return gfx::Insets();
-}
-
-aura::WindowTreeHost* AshRemoteWindowTreeHostWin::AsWindowTreeHost() {
-  return this;
-}
-
-gfx::Transform AshRemoteWindowTreeHostWin::GetRootTransform() const {
-  return transformer_helper_.GetTransform();
-}
-
-void AshRemoteWindowTreeHostWin::SetRootTransform(
-    const gfx::Transform& transform) {
-  transformer_helper_.SetTransform(transform);
-}
-
-gfx::Transform AshRemoteWindowTreeHostWin::GetInverseRootTransform() const {
-  return transformer_helper_.GetInverseTransform();
-}
-
-void AshRemoteWindowTreeHostWin::UpdateRootWindowSize(
-    const gfx::Size& host_size) {
-  transformer_helper_.UpdateWindowSize(host_size);
-}
-
-ui::EventDispatchDetails AshRemoteWindowTreeHostWin::DispatchKeyEventPostIME(
-    ui::KeyEvent* event) {
-  input_method_handler()->SetPostIME(true);
-  ui::EventDispatchDetails details =
-      event_processor()->OnEventFromSource(event);
-  if (!details.dispatcher_destroyed)
-    input_method_handler()->SetPostIME(false);
-  return details;
-}
-
-}  // namespace ash
diff --git a/ash/host/ash_remote_window_tree_host_win.h b/ash/host/ash_remote_window_tree_host_win.h
deleted file mode 100644
index f60e582..0000000
--- a/ash/host/ash_remote_window_tree_host_win.h
+++ /dev/null
@@ -1,53 +0,0 @@
-// Copyright 2014 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 ASH_HOST_REMOTE_WINDOW_TREE_HOST_WIN_H_
-#define ASH_HOST_REMOTE_WINDOW_TREE_HOST_WIN_H_
-
-#include <windows.h>
-
-#include "ash/ash_export.h"
-#include "ash/host/ash_window_tree_host.h"
-#include "ash/host/transformer_helper.h"
-#include "base/macros.h"
-#include "ui/aura/remote_window_tree_host_win.h"
-
-namespace ash {
-
-class ASH_EXPORT AshRemoteWindowTreeHostWin
-    : public AshWindowTreeHost,
-      public aura::RemoteWindowTreeHostWin {
- public:
-  explicit AshRemoteWindowTreeHostWin(HWND remote_hwnd);
-
- private:
-  ~AshRemoteWindowTreeHostWin() override;
-
-  // AshWindowTreeHost:
-  void ToggleFullScreen() override;
-  bool ConfineCursorToRootWindow() override;
-  void UnConfineCursor() override;
-  void SetRootWindowTransformer(
-      scoped_ptr<RootWindowTransformer> transformer) override;
-  gfx::Insets GetHostInsets() const override;
-  aura::WindowTreeHost* AsWindowTreeHost() override;
-
-  // WindowTreeHostWin:
-  gfx::Transform GetRootTransform() const override;
-  void SetRootTransform(const gfx::Transform& transform) override;
-  gfx::Transform GetInverseRootTransform() const override;
-  void UpdateRootWindowSize(const gfx::Size& host_size) override;
-
-  // ui::internal::InputMethodDelegate:
-  ui::EventDispatchDetails DispatchKeyEventPostIME(
-      ui::KeyEvent* event) override;
-
-  TransformerHelper transformer_helper_;
-
-  DISALLOW_COPY_AND_ASSIGN(AshRemoteWindowTreeHostWin);
-};
-
-}  // namespace ash
-
-#endif  // ASH_HOST_REMOTE_WINDOW_TREE_HOST_WIN_H_
diff --git a/ash/host/ash_window_tree_host_win.cc b/ash/host/ash_window_tree_host_win.cc
index 287fc56b..98d6b10 100644
--- a/ash/host/ash_window_tree_host_win.cc
+++ b/ash/host/ash_window_tree_host_win.cc
@@ -6,7 +6,6 @@
 
 #include "ash/ash_export.h"
 #include "ash/ash_switches.h"
-#include "ash/host/ash_remote_window_tree_host_win.h"
 #include "ash/host/ash_window_tree_host_init_params.h"
 #include "ash/host/root_window_transformer.h"
 #include "ash/host/transformer_helper.h"
@@ -123,11 +122,6 @@
 
 AshWindowTreeHost* AshWindowTreeHost::Create(
     const AshWindowTreeHostInitParams& init_params) {
-  if (base::win::GetVersion() >= base::win::VERSION_WIN7 &&
-      !base::CommandLine::ForCurrentProcess()->HasSwitch(
-          ash::switches::kForceAshToDesktop))
-    return new AshRemoteWindowTreeHostWin(init_params.remote_hwnd);
-
   return new AshWindowTreeHostWin(init_params.initial_bounds);
 }
 
diff --git a/ash/test/ash_test_base.cc b/ash/test/ash_test_base.cc
index 4232333..93d770f 100644
--- a/ash/test/ash_test_base.cc
+++ b/ash/test/ash_test_base.cc
@@ -40,7 +40,6 @@
 
 #if defined(OS_WIN)
 #include "base/win/windows_version.h"
-#include "ui/aura/remote_window_tree_host_win.h"
 #include "ui/platform_window/win/win_window.h"
 #include "win8/test/test_registrar_constants.h"
 #endif
diff --git a/base/BUILD.gn b/base/BUILD.gn
index 1265df8..fc441da 100644
--- a/base/BUILD.gn
+++ b/base/BUILD.gn
@@ -1132,7 +1132,7 @@
         "$root_out_dir/msvcr120${vcrt_suffix}.dll",
       ]
       if (is_asan) {
-        data += [ "//third_party/llvm-build/Release+Asserts/lib/clang/3.8.0/lib/windows/clang_rt.asan_dynamic-i386.dll" ]
+        data += [ "//third_party/llvm-build/Release+Asserts/lib/clang/3.9.0/lib/windows/clang_rt.asan_dynamic-i386.dll" ]
       }
     }
 
diff --git a/build/gn_migration.gypi b/build/gn_migration.gypi
index 16e20e0..4399879 100644
--- a/build/gn_migration.gypi
+++ b/build/gn_migration.gypi
@@ -517,7 +517,6 @@
             '../third_party/codesighs/codesighs.gyp:msdump2symdb',
             '../third_party/codesighs/codesighs.gyp:msmap2tsv',
             '../third_party/pdfium/samples/samples.gyp:pdfium_diff',
-            '../win8/win8.gyp:metro_viewer',
           ],
         }],
         ['chromecast==1', {
diff --git a/build/sanitizers/tsan_suppressions.cc b/build/sanitizers/tsan_suppressions.cc
index 475885c..c6b12ba 100644
--- a/build/sanitizers/tsan_suppressions.cc
+++ b/build/sanitizers/tsan_suppressions.cc
@@ -280,6 +280,9 @@
 // https://crbug.com/539315
 "race:MojoCreateMessagePipe\n"
 
+// http://crbug.com/559117
+"race:base::trace_event::TraceConfig::AsConvertableToTraceFormat\n"
+
 // https://crbug.com/569682
 "race:blink::ThreadState::visitStackRoots\n"
 
diff --git a/build/secondary/third_party/crashpad/crashpad/snapshot/BUILD.gn b/build/secondary/third_party/crashpad/crashpad/snapshot/BUILD.gn
index 7cab0432..030e071 100644
--- a/build/secondary/third_party/crashpad/crashpad/snapshot/BUILD.gn
+++ b/build/secondary/third_party/crashpad/crashpad/snapshot/BUILD.gn
@@ -18,6 +18,8 @@
   }
 
   sources = [
+    "api/module_annotations_win.cc",
+    "api/module_annotations_win.h",
     "cpu_architecture.h",
     "cpu_context.cc",
     "cpu_context.h",
diff --git a/build/secondary/third_party/crashpad/crashpad/util/BUILD.gn b/build/secondary/third_party/crashpad/crashpad/util/BUILD.gn
index 8d95f8df..8c01267 100644
--- a/build/secondary/third_party/crashpad/crashpad/util/BUILD.gn
+++ b/build/secondary/third_party/crashpad/crashpad/util/BUILD.gn
@@ -140,6 +140,8 @@
     "win/exception_handler_server.h",
     "win/get_function.cc",
     "win/get_function.h",
+    "win/get_module_information.cc",
+    "win/get_module_information.h",
     "win/handle.cc",
     "win/handle.h",
     "win/module_version.cc",
diff --git a/build/vs_toolchain.py b/build/vs_toolchain.py
index 6a0e6c95..66a3cd8 100755
--- a/build/vs_toolchain.py
+++ b/build/vs_toolchain.py
@@ -71,6 +71,8 @@
   elif sys.platform == 'win32' and not depot_tools_win_toolchain:
     if not 'GYP_MSVS_OVERRIDE_PATH' in os.environ:
       os.environ['GYP_MSVS_OVERRIDE_PATH'] = DetectVisualStudioPath()
+    if not 'GYP_MSVS_VERSION' in os.environ:
+      os.environ['GYP_MSVS_VERSION'] = GetVisualStudioVersion()
 
   return vs_runtime_dll_dirs
 
diff --git a/cc/animation/animation_player.h b/cc/animation/animation_player.h
index 4902ec4..7d04c56 100644
--- a/cc/animation/animation_player.h
+++ b/cc/animation/animation_player.h
@@ -84,6 +84,11 @@
                               Animation::TargetProperty target_property,
                               int group);
 
+  // Whether this player has animations waiting to get sent to LAC.
+  bool has_pending_animations_for_testing() const {
+    return !animations_.empty();
+  }
+
  private:
   friend class base::RefCounted<AnimationPlayer>;
 
diff --git a/cc/blink/web_layer_impl.cc b/cc/blink/web_layer_impl.cc
index 88601b5..56c2af9 100644
--- a/cc/blink/web_layer_impl.cc
+++ b/cc/blink/web_layer_impl.cc
@@ -345,9 +345,58 @@
   return layer_->have_scroll_event_handlers();
 }
 
-void WebLayerImpl::setShouldScrollOnMainThread(
-    bool should_scroll_on_main_thread) {
-  layer_->SetShouldScrollOnMainThread(should_scroll_on_main_thread);
+static_assert(static_cast<cc::InputHandler::MainThreadScrollingReason>(
+                  blink::WebMainThreadScrollingReason::NotScrollingOnMain) ==
+                  cc::InputHandler::NOT_SCROLLING_ON_MAIN,
+              "InputHandler::MainThreadScrollingReason and "
+              "WebMainThreadScrollingReason enums must match");
+static_assert(static_cast<cc::InputHandler::MainThreadScrollingReason>(
+                  blink::WebMainThreadScrollingReason::
+                      HasBackgroundAttachmentFixedObjects) ==
+                  cc::InputHandler::HAS_BACKGROUND_ATTACHMENT_FIXED_OBJECTS,
+              "InputHandler::MainThreadScrollingReason and "
+              "WebMainThreadScrollingReason enums must match");
+static_assert(static_cast<cc::InputHandler::MainThreadScrollingReason>(
+                  blink::WebMainThreadScrollingReason::
+                      HasNonLayerViewportConstrainedObjects) ==
+                  cc::InputHandler::HAS_NON_LAYER_VIEWPORT_CONSTRAINED_OBJECTS,
+              "InputHandler::MainThreadScrollingReason and "
+              "WebMainThreadScrollingReason enums must match");
+static_assert(
+    static_cast<cc::InputHandler::MainThreadScrollingReason>(
+        blink::WebMainThreadScrollingReason::ThreadedScrollingDisabled) ==
+        cc::InputHandler::THREADED_SCROLLING_DISABLED,
+    "InputHandler::MainThreadScrollingReason and "
+    "WebMainThreadScrollingReason enums must match");
+static_assert(static_cast<cc::InputHandler::MainThreadScrollingReason>(
+                  blink::WebMainThreadScrollingReason::ScrollBarScrolling) ==
+                  cc::InputHandler::SCROLL_BAR_SCROLLING,
+              "InputHandler::MainThreadScrollingReason and "
+              "WebMainThreadScrollingReason enums must match");
+static_assert(static_cast<cc::InputHandler::MainThreadScrollingReason>(
+                  blink::WebMainThreadScrollingReason::PageOverlay) ==
+                  cc::InputHandler::PAGE_OVERLAY,
+              "InputHandler::MainThreadScrollingReason and "
+              "WebMainThreadScrollingReason enums must match");
+
+void WebLayerImpl::addMainThreadScrollingReasons(
+    blink::WebMainThreadScrollingReason::WebMainThreadScrollingReason
+        main_thread_scrolling_reasons) {
+  DCHECK(main_thread_scrolling_reasons);
+  // WebLayerImpl should only know about non-transient scrolling
+  // reasons. Transient scrolling reasons are computed per hit test.
+  DCHECK_LE(
+      main_thread_scrolling_reasons,
+      static_cast<
+          blink::WebMainThreadScrollingReason::WebMainThreadScrollingReason>(
+          cc::InputHandler::MaxNonTransientScrollingReason));
+  layer_->AddMainThreadScrollingReasons(
+      static_cast<cc::InputHandler::MainThreadScrollingReason>(
+          main_thread_scrolling_reasons));
+}
+
+void WebLayerImpl::clearMainThreadScrollingReasons() {
+  layer_->ClearMainThreadScrollingReasons();
 }
 
 bool WebLayerImpl::shouldScrollOnMainThread() const {
diff --git a/cc/blink/web_layer_impl.h b/cc/blink/web_layer_impl.h
index 3fd0bcc..482c633 100644
--- a/cc/blink/web_layer_impl.h
+++ b/cc/blink/web_layer_impl.h
@@ -22,6 +22,7 @@
 #include "third_party/WebKit/public/platform/WebDoublePoint.h"
 #include "third_party/WebKit/public/platform/WebFloatPoint.h"
 #include "third_party/WebKit/public/platform/WebLayer.h"
+#include "third_party/WebKit/public/platform/WebMainThreadScrollingReason.h"
 #include "third_party/WebKit/public/platform/WebPoint.h"
 #include "third_party/WebKit/public/platform/WebRect.h"
 #include "third_party/WebKit/public/platform/WebSize.h"
@@ -128,7 +129,10 @@
   bool haveWheelEventHandlers() const override;
   void setHaveScrollEventHandlers(bool have_scroll_event_handlers) override;
   bool haveScrollEventHandlers() const override;
-  void setShouldScrollOnMainThread(bool scroll_on_main) override;
+  void addMainThreadScrollingReasons(
+      blink::WebMainThreadScrollingReason::WebMainThreadScrollingReason
+          main_thread_scrolling_reasons) override;
+  void clearMainThreadScrollingReasons() override;
   bool shouldScrollOnMainThread() const override;
   void setNonFastScrollableRegion(
       const blink::WebVector<blink::WebRect>& region) override;
diff --git a/cc/input/input_handler.h b/cc/input/input_handler.h
index f65509f..d26e6a4b 100644
--- a/cc/input/input_handler.h
+++ b/cc/input/input_handler.h
@@ -77,14 +77,51 @@
  public:
   // Note these are used in a histogram. Do not reorder or delete existing
   // entries.
-  enum ScrollStatus {
+  enum ScrollThread {
     SCROLL_ON_MAIN_THREAD = 0,
-    SCROLL_STARTED,
+    SCROLL_ON_IMPL_THREAD,
     SCROLL_IGNORED,
     SCROLL_UNKNOWN,
     // This must be the last entry.
     ScrollStatusCount
   };
+
+  // Ensure this stays in sync with MainThreadScrollingReason in histograms.xml,
+  // and that this extends ScrollingCoordinator::MainThreadScrollingReason.
+  // ScrollingCoordinator::MainThreadScrollingReason contains the flags
+  // which are associated with a layer. The flags only contained in
+  // InputHandler::MainThreadScrollingReason are computed for each scroll
+  // begin.
+  enum MainThreadScrollingReason {
+    NOT_SCROLLING_ON_MAIN = 0,
+    HAS_BACKGROUND_ATTACHMENT_FIXED_OBJECTS = 1 << 0,
+    HAS_NON_LAYER_VIEWPORT_CONSTRAINED_OBJECTS = 1 << 1,
+    THREADED_SCROLLING_DISABLED = 1 << 2,
+    SCROLL_BAR_SCROLLING = 1 << 3,
+    PAGE_OVERLAY = 1 << 4,
+    MaxNonTransientScrollingReason = PAGE_OVERLAY,
+    NON_FAST_SCROLLABLE_REGION = 1 << 5,
+    EVENT_HANDLERS = 1 << 6,
+    FAILED_HIT_TEST = 1 << 7,
+    NO_SCROLLING_LAYER = 1 << 8,
+    NOT_SCROLLABLE = 1 << 9,
+    CONTINUING_MAIN_THREAD_SCROLL = 1 << 10,
+    NON_INVERTIBLE_TRANSFORM = 1 << 11,
+    MainThreadScrollingReasonCount = 13
+  };
+
+  struct ScrollStatus {
+    ScrollStatus()
+        : thread(SCROLL_ON_IMPL_THREAD),
+          main_thread_scrolling_reasons(NOT_SCROLLING_ON_MAIN) {}
+    ScrollStatus(ScrollThread thread,
+                 MainThreadScrollingReason main_thread_scrolling_reasons)
+        : thread(thread),
+          main_thread_scrolling_reasons(main_thread_scrolling_reasons) {}
+    ScrollThread thread;
+    MainThreadScrollingReason main_thread_scrolling_reasons;
+  };
+
   enum ScrollInputType { GESTURE, WHEEL, ANIMATED_WHEEL, NON_BUBBLING_GESTURE };
 
   // Binds a client to this handler to receive notifications. Only one client
@@ -181,6 +218,13 @@
   DISALLOW_COPY_AND_ASSIGN(InputHandler);
 };
 
+inline const InputHandler::MainThreadScrollingReason& operator|=(
+    InputHandler::MainThreadScrollingReason& a,
+    InputHandler::MainThreadScrollingReason b) {
+  return a = static_cast<InputHandler::MainThreadScrollingReason>(
+             static_cast<unsigned>(a) | static_cast<unsigned>(b));
+}
+
 }  // namespace cc
 
 #endif  // CC_INPUT_INPUT_HANDLER_H_
diff --git a/cc/layers/layer.cc b/cc/layers/layer.cc
index cc2cbbb..88043a7 100644
--- a/cc/layers/layer.cc
+++ b/cc/layers/layer.cc
@@ -66,8 +66,8 @@
       property_tree_sequence_number_(-1),
       element_id_(0),
       mutable_properties_(kMutablePropertyNone),
+      main_thread_scrolling_reasons_(InputHandler::NOT_SCROLLING_ON_MAIN),
       should_flatten_transform_from_property_tree_(false),
-      should_scroll_on_main_thread_(false),
       have_wheel_event_handlers_(false),
       have_scroll_event_handlers_(false),
       user_scrollable_horizontal_(true),
@@ -947,11 +947,21 @@
   SetNeedsCommit();
 }
 
-void Layer::SetShouldScrollOnMainThread(bool should_scroll_on_main_thread) {
+void Layer::AddMainThreadScrollingReasons(
+    InputHandler::MainThreadScrollingReason main_thread_scrolling_reasons) {
   DCHECK(IsPropertyChangeAllowed());
-  if (should_scroll_on_main_thread_ == should_scroll_on_main_thread)
+  DCHECK(main_thread_scrolling_reasons);
+  if (main_thread_scrolling_reasons_ == main_thread_scrolling_reasons)
     return;
-  should_scroll_on_main_thread_ = should_scroll_on_main_thread;
+  main_thread_scrolling_reasons_ |= main_thread_scrolling_reasons;
+  SetNeedsCommit();
+}
+
+void Layer::ClearMainThreadScrollingReasons() {
+  DCHECK(IsPropertyChangeAllowed());
+  if (!main_thread_scrolling_reasons_)
+    return;
+  main_thread_scrolling_reasons_ = InputHandler::NOT_SCROLLING_ON_MAIN;
   SetNeedsCommit();
 }
 
@@ -1196,7 +1206,7 @@
   DCHECK(!(FilterIsAnimating() && layer->FilterIsAnimatingOnImplOnly()));
   layer->SetBackgroundFilters(background_filters());
   layer->SetMasksToBounds(masks_to_bounds_);
-  layer->SetShouldScrollOnMainThread(should_scroll_on_main_thread_);
+  layer->set_main_thread_scrolling_reasons(main_thread_scrolling_reasons_);
   layer->SetHaveWheelEventHandlers(have_wheel_event_handlers_);
   layer->SetHaveScrollEventHandlers(have_scroll_event_handlers_);
   layer->SetNonFastScrollableRegion(non_fast_scrollable_region_);
@@ -1467,7 +1477,7 @@
   // |filters_| and |background_filters_|. See crbug.com/541321.
 
   base->set_masks_to_bounds(masks_to_bounds_);
-  base->set_should_scroll_on_main_thread(should_scroll_on_main_thread_);
+  base->set_main_thread_scrolling_reasons(main_thread_scrolling_reasons_);
   base->set_have_wheel_event_handlers(have_wheel_event_handlers_);
   base->set_have_scroll_event_handlers(have_scroll_event_handlers_);
   RegionToProto(non_fast_scrollable_region_,
@@ -1553,7 +1563,9 @@
   hide_layer_and_subtree_ = base.hide_layer_and_subtree();
   has_render_surface_ = base.has_render_surface();
   masks_to_bounds_ = base.masks_to_bounds();
-  should_scroll_on_main_thread_ = base.should_scroll_on_main_thread();
+  main_thread_scrolling_reasons_ =
+      static_cast<InputHandler::MainThreadScrollingReason>(
+          base.main_thread_scrolling_reasons());
   have_wheel_event_handlers_ = base.have_wheel_event_handlers();
   have_scroll_event_handlers_ = base.have_scroll_event_handlers();
   non_fast_scrollable_region_ =
diff --git a/cc/layers/layer.h b/cc/layers/layer.h
index ef5da33..aff32fa 100644
--- a/cc/layers/layer.h
+++ b/cc/layers/layer.h
@@ -23,6 +23,7 @@
 #include "cc/base/region.h"
 #include "cc/debug/frame_timing_request.h"
 #include "cc/debug/micro_benchmark.h"
+#include "cc/input/input_handler.h"
 #include "cc/layers/layer_lists.h"
 #include "cc/layers/layer_position_constraint.h"
 #include "cc/layers/paint_properties.h"
@@ -276,9 +277,11 @@
   }
   bool user_scrollable_vertical() const { return user_scrollable_vertical_; }
 
-  void SetShouldScrollOnMainThread(bool should_scroll_on_main_thread);
+  void AddMainThreadScrollingReasons(
+      InputHandler::MainThreadScrollingReason main_thread_scrolling_reasons);
+  void ClearMainThreadScrollingReasons();
   bool should_scroll_on_main_thread() const {
-    return should_scroll_on_main_thread_;
+    return !!main_thread_scrolling_reasons_;
   }
 
   void SetHaveWheelEventHandlers(bool have_wheel_event_handlers);
@@ -723,8 +726,8 @@
   uint64_t element_id_;
   uint32_t mutable_properties_;
   gfx::Vector2dF offset_to_transform_parent_;
+  InputHandler::MainThreadScrollingReason main_thread_scrolling_reasons_;
   bool should_flatten_transform_from_property_tree_ : 1;
-  bool should_scroll_on_main_thread_ : 1;
   bool have_wheel_event_handlers_ : 1;
   bool have_scroll_event_handlers_ : 1;
   bool user_scrollable_horizontal_ : 1;
diff --git a/cc/layers/layer_impl.cc b/cc/layers/layer_impl.cc
index b845968..422de5c 100644
--- a/cc/layers/layer_impl.cc
+++ b/cc/layers/layer_impl.cc
@@ -57,7 +57,7 @@
       layer_tree_impl_(tree_impl),
       scroll_offset_(scroll_offset),
       scroll_clip_layer_id_(Layer::INVALID_ID),
-      should_scroll_on_main_thread_(false),
+      main_thread_scrolling_reasons_(InputHandler::NOT_SCROLLING_ON_MAIN),
       have_wheel_event_handlers_(false),
       have_scroll_event_handlers_(false),
       scroll_blocks_on_(SCROLL_BLOCKS_ON_NONE),
@@ -507,15 +507,24 @@
     const gfx::PointF& screen_space_point,
     InputHandler::ScrollInputType type,
     ScrollBlocksOn effective_block_mode) const {
+  InputHandler::ScrollStatus scroll_status;
+  scroll_status.main_thread_scrolling_reasons =
+      InputHandler::NOT_SCROLLING_ON_MAIN;
   if (should_scroll_on_main_thread()) {
     TRACE_EVENT0("cc", "LayerImpl::TryScroll: Failed ShouldScrollOnMainThread");
-    return InputHandler::SCROLL_ON_MAIN_THREAD;
+    scroll_status.thread = InputHandler::SCROLL_ON_MAIN_THREAD;
+    scroll_status.main_thread_scrolling_reasons =
+        main_thread_scrolling_reasons_;
+    return scroll_status;
   }
 
   gfx::Transform screen_space_transform = ScreenSpaceTransform();
   if (!screen_space_transform.IsInvertible()) {
     TRACE_EVENT0("cc", "LayerImpl::TryScroll: Ignored NonInvertibleTransform");
-    return InputHandler::SCROLL_IGNORED;
+    scroll_status.thread = InputHandler::SCROLL_IGNORED;
+    scroll_status.main_thread_scrolling_reasons =
+        InputHandler::NON_INVERTIBLE_TRANSFORM;
+    return scroll_status;
   }
 
   if (!non_fast_scrollable_region().IsEmpty()) {
@@ -535,26 +544,35 @@
             gfx::ToRoundedPoint(hit_test_point_in_layer_space))) {
       TRACE_EVENT0("cc",
                    "LayerImpl::tryScroll: Failed NonFastScrollableRegion");
-      return InputHandler::SCROLL_ON_MAIN_THREAD;
+      scroll_status.thread = InputHandler::SCROLL_ON_MAIN_THREAD;
+      scroll_status.main_thread_scrolling_reasons =
+          InputHandler::NON_FAST_SCROLLABLE_REGION;
+      return scroll_status;
     }
   }
 
   if (have_scroll_event_handlers() &&
       effective_block_mode & SCROLL_BLOCKS_ON_SCROLL_EVENT) {
     TRACE_EVENT0("cc", "LayerImpl::tryScroll: Failed ScrollEventHandlers");
-    return InputHandler::SCROLL_ON_MAIN_THREAD;
+    scroll_status.thread = InputHandler::SCROLL_ON_MAIN_THREAD;
+    scroll_status.main_thread_scrolling_reasons = InputHandler::EVENT_HANDLERS;
+    return scroll_status;
   }
 
   if ((type == InputHandler::WHEEL || type == InputHandler::ANIMATED_WHEEL) &&
       have_wheel_event_handlers() &&
       effective_block_mode & SCROLL_BLOCKS_ON_WHEEL_EVENT) {
     TRACE_EVENT0("cc", "LayerImpl::tryScroll: Failed WheelEventHandlers");
-    return InputHandler::SCROLL_ON_MAIN_THREAD;
+    scroll_status.thread = InputHandler::SCROLL_ON_MAIN_THREAD;
+    scroll_status.main_thread_scrolling_reasons = InputHandler::EVENT_HANDLERS;
+    return scroll_status;
   }
 
   if (!scrollable()) {
     TRACE_EVENT0("cc", "LayerImpl::tryScroll: Ignored not scrollable");
-    return InputHandler::SCROLL_IGNORED;
+    scroll_status.thread = InputHandler::SCROLL_IGNORED;
+    scroll_status.main_thread_scrolling_reasons = InputHandler::NOT_SCROLLABLE;
+    return scroll_status;
   }
 
   gfx::ScrollOffset max_scroll_offset = MaxScrollOffset();
@@ -562,10 +580,13 @@
     TRACE_EVENT0("cc",
                  "LayerImpl::tryScroll: Ignored. Technically scrollable,"
                  " but has no affordance in either direction.");
-    return InputHandler::SCROLL_IGNORED;
+    scroll_status.thread = InputHandler::SCROLL_IGNORED;
+    scroll_status.main_thread_scrolling_reasons = InputHandler::NOT_SCROLLABLE;
+    return scroll_status;
   }
 
-  return InputHandler::SCROLL_STARTED;
+  scroll_status.thread = InputHandler::SCROLL_ON_IMPL_THREAD;
+  return scroll_status;
 }
 
 skia::RefPtr<SkPicture> LayerImpl::GetPicture() {
@@ -594,7 +615,7 @@
   layer->SetFilters(filters());
   layer->SetBackgroundFilters(background_filters());
   layer->SetMasksToBounds(masks_to_bounds_);
-  layer->SetShouldScrollOnMainThread(should_scroll_on_main_thread_);
+  layer->set_main_thread_scrolling_reasons(main_thread_scrolling_reasons_);
   layer->SetHaveWheelEventHandlers(have_wheel_event_handlers_);
   layer->SetHaveScrollEventHandlers(have_scroll_event_handlers_);
   layer->SetScrollBlocksOn(scroll_blocks_on_);
diff --git a/cc/layers/layer_impl.h b/cc/layers/layer_impl.h
index 4dca350..48e9529 100644
--- a/cc/layers/layer_impl.h
+++ b/cc/layers/layer_impl.h
@@ -492,11 +492,12 @@
 
   void ApplySentScrollDeltasFromAbortedCommit();
 
-  void SetShouldScrollOnMainThread(bool should_scroll_on_main_thread) {
-    should_scroll_on_main_thread_ = should_scroll_on_main_thread;
+  void set_main_thread_scrolling_reasons(
+      InputHandler::MainThreadScrollingReason main_thread_scrolling_reasons) {
+    main_thread_scrolling_reasons_ = main_thread_scrolling_reasons;
   }
   bool should_scroll_on_main_thread() const {
-    return should_scroll_on_main_thread_;
+    return !!main_thread_scrolling_reasons_;
   }
 
   void SetHaveWheelEventHandlers(bool have_wheel_event_handlers) {
@@ -773,8 +774,7 @@
   int scroll_clip_layer_id_;
 
   gfx::Vector2dF offset_to_transform_parent_;
-
-  bool should_scroll_on_main_thread_ : 1;
+  InputHandler::MainThreadScrollingReason main_thread_scrolling_reasons_;
   bool have_wheel_event_handlers_ : 1;
   bool have_scroll_event_handlers_ : 1;
 
diff --git a/cc/layers/layer_unittest.cc b/cc/layers/layer_unittest.cc
index f73cb25..13bcba1 100644
--- a/cc/layers/layer_unittest.cc
+++ b/cc/layers/layer_unittest.cc
@@ -131,8 +131,8 @@
     EXPECT_EQ(src->hide_layer_and_subtree_, dest->hide_layer_and_subtree_);
     EXPECT_EQ(src->has_render_surface_, dest->has_render_surface_);
     EXPECT_EQ(src->masks_to_bounds_, dest->masks_to_bounds_);
-    EXPECT_EQ(src->should_scroll_on_main_thread_,
-              dest->should_scroll_on_main_thread_);
+    EXPECT_EQ(src->main_thread_scrolling_reasons_,
+              dest->main_thread_scrolling_reasons_);
     EXPECT_EQ(src->have_wheel_event_handlers_,
               dest->have_wheel_event_handlers_);
     EXPECT_EQ(src->have_scroll_event_handlers_,
@@ -249,7 +249,7 @@
     layer->hide_layer_and_subtree_ = false;
     layer->has_render_surface_ = false;
     layer->masks_to_bounds_ = true;
-    layer->should_scroll_on_main_thread_ = false;
+    layer->main_thread_scrolling_reasons_ = InputHandler::NOT_SCROLLING_ON_MAIN;
     layer->have_wheel_event_handlers_ = true;
     layer->have_scroll_event_handlers_ = false;
     layer->non_fast_scrollable_region_ = Region(gfx::Rect(5, 1, 14, 3));
@@ -299,8 +299,8 @@
     layer->hide_layer_and_subtree_ = !layer->hide_layer_and_subtree_;
     layer->has_render_surface_ = !layer->has_render_surface_;
     layer->masks_to_bounds_ = !layer->masks_to_bounds_;
-    layer->should_scroll_on_main_thread_ =
-        !layer->should_scroll_on_main_thread_;
+    layer->main_thread_scrolling_reasons_ =
+        InputHandler::HAS_BACKGROUND_ATTACHMENT_FIXED_OBJECTS;
     layer->have_wheel_event_handlers_ = !layer->have_wheel_event_handlers_;
     layer->have_scroll_event_handlers_ = !layer->have_scroll_event_handlers_;
     layer->non_fast_scrollable_region_ = Region(gfx::Rect(5, 1, 14, 3));
@@ -967,7 +967,8 @@
   EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetUserScrollable(true, false));
   EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetScrollOffset(
       gfx::ScrollOffset(10, 10)));
-  EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetShouldScrollOnMainThread(true));
+  EXPECT_SET_NEEDS_COMMIT(1, test_layer->AddMainThreadScrollingReasons(
+                                 InputHandler::EVENT_HANDLERS));
   EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetNonFastScrollableRegion(
       Region(gfx::Rect(1, 1, 2, 2))));
   EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetHaveWheelEventHandlers(true));
diff --git a/cc/layers/painted_scrollbar_layer.cc b/cc/layers/painted_scrollbar_layer.cc
index aabde35..2e822599 100644
--- a/cc/layers/painted_scrollbar_layer.cc
+++ b/cc/layers/painted_scrollbar_layer.cc
@@ -50,7 +50,7 @@
       has_thumb_(scrollbar_->HasThumb()),
       thumb_opacity_(scrollbar_->ThumbOpacity()) {
   if (!scrollbar_->IsOverlay())
-    SetShouldScrollOnMainThread(true);
+    AddMainThreadScrollingReasons(InputHandler::SCROLL_BAR_SCROLLING);
 }
 
 PaintedScrollbarLayer::~PaintedScrollbarLayer() {}
diff --git a/cc/layers/scrollbar_layer_unittest.cc b/cc/layers/scrollbar_layer_unittest.cc
index b9fc9ae..e0d7a74b 100644
--- a/cc/layers/scrollbar_layer_unittest.cc
+++ b/cc/layers/scrollbar_layer_unittest.cc
@@ -160,9 +160,11 @@
   // When the scrollbar is not an overlay scrollbar, the scroll should be
   // responded to on the main thread as the compositor does not yet implement
   // scrollbar scrolling.
-  EXPECT_EQ(InputHandler::SCROLL_ON_MAIN_THREAD,
-            scrollbar_layer_impl->TryScroll(
-                gfx::PointF(), InputHandler::GESTURE, SCROLL_BLOCKS_ON_NONE));
+  InputHandler::ScrollStatus status = scrollbar_layer_impl->TryScroll(
+      gfx::PointF(), InputHandler::GESTURE, SCROLL_BLOCKS_ON_NONE);
+  EXPECT_EQ(InputHandler::SCROLL_ON_MAIN_THREAD, status.thread);
+  EXPECT_EQ(InputHandler::SCROLL_BAR_SCROLLING,
+            status.main_thread_scrolling_reasons);
 
   // Create and attach an overlay scrollbar.
   scrollbar.reset(new FakeScrollbar(false, false, true));
@@ -175,9 +177,10 @@
 
   // The user shouldn't be able to drag an overlay scrollbar and the scroll
   // may be handled in the compositor.
-  EXPECT_EQ(InputHandler::SCROLL_IGNORED,
-            scrollbar_layer_impl->TryScroll(
-                gfx::PointF(), InputHandler::GESTURE, SCROLL_BLOCKS_ON_NONE));
+  status = scrollbar_layer_impl->TryScroll(gfx::PointF(), InputHandler::GESTURE,
+                                           SCROLL_BLOCKS_ON_NONE);
+  EXPECT_EQ(InputHandler::SCROLL_IGNORED, status.thread);
+  EXPECT_EQ(InputHandler::NOT_SCROLLABLE, status.main_thread_scrolling_reasons);
 }
 
 TEST_F(ScrollbarLayerTest, ScrollOffsetSynchronization) {
diff --git a/cc/proto/layer.proto b/cc/proto/layer.proto
index bc1255d..4c8ba319 100644
--- a/cc/proto/layer.proto
+++ b/cc/proto/layer.proto
@@ -85,7 +85,7 @@
   // repeated FilterOperation filters = 12;
   // repeated FilterOperation background_filters = 13;
   optional bool masks_to_bounds = 14;
-  optional bool should_scroll_on_main_thread = 15;
+  optional uint32 main_thread_scrolling_reasons = 15;
   optional bool have_wheel_event_handlers = 16;
   optional bool have_scroll_event_handlers = 17;
   optional Region non_fast_scrollable_region = 18;
diff --git a/cc/trees/layer_tree_host_impl.cc b/cc/trees/layer_tree_host_impl.cc
index 057228f0..2d1321e0 100644
--- a/cc/trees/layer_tree_host_impl.cc
+++ b/cc/trees/layer_tree_host_impl.cc
@@ -140,7 +140,7 @@
 
 void RecordCompositorSlowScrollMetric(InputHandler::ScrollInputType type,
                                       ScrollThread scroll_thread) {
-  bool scroll_on_main_thread = (scroll_thread == ScrollThread::MAIN_THREAD);
+  bool scroll_on_main_thread = (scroll_thread == MAIN_THREAD);
   if (type == InputHandler::WHEEL || type == InputHandler::ANIMATED_WHEEL) {
     UMA_HISTOGRAM_BOOLEAN("Renderer4.CompositorWheelScrollUpdateThread",
                           scroll_on_main_thread);
@@ -548,8 +548,10 @@
       active_tree_->FindLayerThatIsHitByPoint(device_viewport_point);
 
   bool scroll_on_main_thread = false;
+  InputHandler::MainThreadScrollingReason main_thread_scrolling_reasons;
   LayerImpl* test_layer_impl = FindScrollLayerForDeviceViewportPoint(
-      device_viewport_point, type, layer_impl, &scroll_on_main_thread, NULL);
+      device_viewport_point, type, layer_impl, &scroll_on_main_thread, nullptr,
+      &main_thread_scrolling_reasons);
 
   if (!test_layer_impl)
     return false;
@@ -2476,8 +2478,12 @@
     InputHandler::ScrollInputType type,
     LayerImpl* layer_impl,
     bool* scroll_on_main_thread,
-    bool* optional_has_ancestor_scroll_handler) const {
+    bool* optional_has_ancestor_scroll_handler,
+    InputHandler::MainThreadScrollingReason* main_thread_scrolling_reasons)
+    const {
   DCHECK(scroll_on_main_thread);
+  DCHECK(main_thread_scrolling_reasons);
+  *main_thread_scrolling_reasons = InputHandler::NOT_SCROLLING_ON_MAIN;
 
   ScrollBlocksOn block_mode = EffectiveScrollBlocksOn(layer_impl);
 
@@ -2488,8 +2494,17 @@
     // thread.
     ScrollStatus status =
         layer_impl->TryScroll(device_viewport_point, type, block_mode);
-    if (status == SCROLL_ON_MAIN_THREAD) {
+    if (status.thread == SCROLL_ON_MAIN_THREAD) {
+      if (layer_impl->should_scroll_on_main_thread()) {
+        DCHECK(status.main_thread_scrolling_reasons <=
+               InputHandler::MaxNonTransientScrollingReason);
+      } else {
+        DCHECK(status.main_thread_scrolling_reasons >
+               InputHandler::MaxNonTransientScrollingReason);
+      }
+
       *scroll_on_main_thread = true;
+      *main_thread_scrolling_reasons = status.main_thread_scrolling_reasons;
       return NULL;
     }
 
@@ -2499,9 +2514,19 @@
 
     status =
         scroll_layer_impl->TryScroll(device_viewport_point, type, block_mode);
+
     // If any layer wants to divert the scroll event to the main thread, abort.
-    if (status == SCROLL_ON_MAIN_THREAD) {
+    if (status.thread == SCROLL_ON_MAIN_THREAD) {
+      if (layer_impl->should_scroll_on_main_thread()) {
+        DCHECK(status.main_thread_scrolling_reasons <=
+               InputHandler::MaxNonTransientScrollingReason);
+      } else {
+        DCHECK(status.main_thread_scrolling_reasons >
+               InputHandler::MaxNonTransientScrollingReason);
+      }
+
       *scroll_on_main_thread = true;
+      *main_thread_scrolling_reasons = status.main_thread_scrolling_reasons;
       return NULL;
     }
 
@@ -2509,8 +2534,10 @@
         scroll_layer_impl->have_scroll_event_handlers())
       *optional_has_ancestor_scroll_handler = true;
 
-    if (status == SCROLL_STARTED && !potentially_scrolling_layer_impl)
+    if (status.thread == InputHandler::SCROLL_ON_IMPL_THREAD &&
+        !potentially_scrolling_layer_impl) {
       potentially_scrolling_layer_impl = scroll_layer_impl;
+    }
   }
 
   // Falling back to the root scroll layer ensures generation of root overscroll
@@ -2553,9 +2580,14 @@
   DCHECK(scroll_state);
   DCHECK(scroll_state->delta_x() == 0 && scroll_state->delta_y() == 0);
 
-  if (!scrolling_layer_impl)
-    return SCROLL_IGNORED;
-
+  InputHandler::ScrollStatus scroll_status;
+  scroll_status.main_thread_scrolling_reasons = NOT_SCROLLING_ON_MAIN;
+  if (!scrolling_layer_impl) {
+    scroll_status.thread = SCROLL_IGNORED;
+    scroll_status.main_thread_scrolling_reasons = NO_SCROLLING_LAYER;
+    return scroll_status;
+  }
+  scroll_status.thread = SCROLL_ON_IMPL_THREAD;
   ScrollAnimationAbort(scrolling_layer_impl);
 
   top_controls_manager_->ScrollBegin();
@@ -2570,12 +2602,12 @@
   DistributeScrollDelta(scroll_state);
 
   client_->RenewTreePriority();
-  RecordCompositorSlowScrollMetric(type, ScrollThread::CC_THREAD);
+  RecordCompositorSlowScrollMetric(type, CC_THREAD);
 
   // TODO(lanwei): Will remove this metric in M50 when we have used the new
   // metrics for one milestone, see https://crbug.com/557787.
   UMA_HISTOGRAM_BOOLEAN("TryScroll.SlowScroll", false);
-  return SCROLL_STARTED;
+  return scroll_status;
 }
 
 InputHandler::ScrollStatus LayerTreeHostImpl::RootScrollBegin(
@@ -2591,6 +2623,8 @@
 InputHandler::ScrollStatus LayerTreeHostImpl::ScrollBegin(
     ScrollState* scroll_state,
     InputHandler::ScrollInputType type) {
+  ScrollStatus scroll_status;
+  scroll_status.main_thread_scrolling_reasons = NOT_SCROLLING_ON_MAIN;
   TRACE_EVENT0("cc", "LayerTreeHostImpl::ScrollBegin");
 
   ClearCurrentlyScrollingLayer();
@@ -2607,22 +2641,29 @@
     LayerImpl* scroll_layer_impl =
         active_tree_->FindFirstScrollingLayerThatIsHitByPoint(
             device_viewport_point);
-    if (scroll_layer_impl && !HasScrollAncestor(layer_impl, scroll_layer_impl))
-      return SCROLL_UNKNOWN;
+    if (scroll_layer_impl &&
+        !HasScrollAncestor(layer_impl, scroll_layer_impl)) {
+      scroll_status.thread = SCROLL_UNKNOWN;
+      scroll_status.main_thread_scrolling_reasons =
+          InputHandler::FAILED_HIT_TEST;
+      return scroll_status;
+    }
   }
 
   bool scroll_on_main_thread = false;
   LayerImpl* scrolling_layer_impl = FindScrollLayerForDeviceViewportPoint(
       device_viewport_point, type, layer_impl, &scroll_on_main_thread,
-      &scroll_affects_scroll_handler_);
+      &scroll_affects_scroll_handler_,
+      &scroll_status.main_thread_scrolling_reasons);
 
   if (scroll_on_main_thread) {
-    RecordCompositorSlowScrollMetric(type, ScrollThread::MAIN_THREAD);
+    RecordCompositorSlowScrollMetric(type, MAIN_THREAD);
 
     // TODO(lanwei): Will remove this metric in M50 when we have used the new
     // metrics for one milestone, see https://crbug.com/557787.
     UMA_HISTOGRAM_BOOLEAN("TryScroll.SlowScroll", true);
-    return SCROLL_ON_MAIN_THREAD;
+    scroll_status.thread = SCROLL_ON_MAIN_THREAD;
+    return scroll_status;
   }
 
   return ScrollBeginImpl(scroll_state, scrolling_layer_impl, type);
@@ -2631,10 +2672,16 @@
 InputHandler::ScrollStatus LayerTreeHostImpl::ScrollAnimated(
     const gfx::Point& viewport_point,
     const gfx::Vector2dF& scroll_delta) {
+  InputHandler::ScrollStatus scroll_status;
+  scroll_status.main_thread_scrolling_reasons = NOT_SCROLLING_ON_MAIN;
   if (LayerImpl* layer_impl = CurrentlyScrollingLayer()) {
-    return ScrollAnimationUpdateTarget(layer_impl, scroll_delta)
-               ? SCROLL_STARTED
-               : SCROLL_IGNORED;
+    if (ScrollAnimationUpdateTarget(layer_impl, scroll_delta)) {
+      scroll_status.thread = SCROLL_ON_IMPL_THREAD;
+    } else {
+      scroll_status.thread = SCROLL_IGNORED;
+      scroll_status.main_thread_scrolling_reasons = NOT_SCROLLABLE;
+    }
+    return scroll_status;
   }
 
   ScrollState scroll_state(0, 0, viewport_point.x(), viewport_point.y(), 0, 0,
@@ -2643,9 +2690,8 @@
   // that can scroll and set up an animation of its scroll offset. Note that
   // this does not currently go through the scroll customization and viewport
   // machinery that ScrollBy uses for non-animated wheel scrolls.
-  InputHandler::ScrollStatus scroll_status =
-      ScrollBegin(&scroll_state, ANIMATED_WHEEL);
-  if (scroll_status == SCROLL_STARTED) {
+  scroll_status = ScrollBegin(&scroll_state, ANIMATED_WHEEL);
+  if (scroll_status.thread == SCROLL_ON_IMPL_THREAD) {
     gfx::Vector2dF pending_delta = scroll_delta;
     for (LayerImpl* layer_impl = CurrentlyScrollingLayer(); layer_impl;
          layer_impl = NextLayerInScrollOrder(layer_impl)) {
@@ -2674,7 +2720,7 @@
       ScrollAnimationCreate(layer_impl, target_offset, current_offset);
 
       SetNeedsOneBeginImplFrame();
-      return SCROLL_STARTED;
+      return scroll_status;
     }
   }
   scroll_state.set_is_ending(true);
@@ -3006,9 +3052,16 @@
 }
 
 InputHandler::ScrollStatus LayerTreeHostImpl::FlingScrollBegin() {
-  if (!CurrentlyScrollingLayer())
-    return SCROLL_IGNORED;
-  return SCROLL_STARTED;
+  InputHandler::ScrollStatus scroll_status;
+  scroll_status.main_thread_scrolling_reasons =
+      InputHandler::NOT_SCROLLING_ON_MAIN;
+  if (!CurrentlyScrollingLayer()) {
+    scroll_status.thread = SCROLL_IGNORED;
+    scroll_status.main_thread_scrolling_reasons = NO_SCROLLING_LAYER;
+  } else {
+    scroll_status.thread = SCROLL_ON_IMPL_THREAD;
+  }
+  return scroll_status;
 }
 
 float LayerTreeHostImpl::DeviceSpaceDistanceToLayer(
@@ -3036,9 +3089,10 @@
     return;
 
   bool scroll_on_main_thread = false;
+  InputHandler::MainThreadScrollingReason main_thread_scrolling_reasons;
   LayerImpl* scroll_layer_impl = FindScrollLayerForDeviceViewportPoint(
       device_viewport_point, InputHandler::GESTURE, layer_impl,
-      &scroll_on_main_thread, NULL);
+      &scroll_on_main_thread, NULL, &main_thread_scrolling_reasons);
   if (scroll_layer_impl == InnerViewportScrollLayer())
     scroll_layer_impl = OuterViewportScrollLayer();
   if (scroll_on_main_thread || !scroll_layer_impl)
diff --git a/cc/trees/layer_tree_host_impl.h b/cc/trees/layer_tree_host_impl.h
index 6d78c16..1e0f7f6 100644
--- a/cc/trees/layer_tree_host_impl.h
+++ b/cc/trees/layer_tree_host_impl.h
@@ -683,7 +683,9 @@
       InputHandler::ScrollInputType type,
       LayerImpl* layer_hit_by_point,
       bool* scroll_on_main_thread,
-      bool* optional_has_ancestor_scroll_handler) const;
+      bool* optional_has_ancestor_scroll_handler,
+      InputHandler::MainThreadScrollingReason* main_thread_scrolling_reason)
+      const;
   float DeviceSpaceDistanceToLayer(const gfx::PointF& device_viewport_point,
                                    LayerImpl* layer_impl);
   void StartScrollbarFadeRecursive(LayerImpl* layer);
diff --git a/cc/trees/layer_tree_host_impl_unittest.cc b/cc/trees/layer_tree_host_impl_unittest.cc
index 814279e..72a3354 100644
--- a/cc/trees/layer_tree_host_impl_unittest.cc
+++ b/cc/trees/layer_tree_host_impl_unittest.cc
@@ -621,9 +621,12 @@
   host_impl_->SetViewportSize(gfx::Size(50, 50));
   DrawFrame();
 
-  EXPECT_EQ(InputHandler::SCROLL_STARTED,
-            host_impl_->ScrollBegin(BeginState(gfx::Point()).get(),
-                                    InputHandler::WHEEL));
+  InputHandler::ScrollStatus status = host_impl_->ScrollBegin(
+      BeginState(gfx::Point()).get(), InputHandler::WHEEL);
+  EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, status.thread);
+  EXPECT_EQ(InputHandler::NOT_SCROLLING_ON_MAIN,
+            status.main_thread_scrolling_reasons);
+
   EXPECT_TRUE(host_impl_->IsCurrentlyScrollingLayerAt(gfx::Point(),
                                                       InputHandler::WHEEL));
   host_impl_->ScrollBy(UpdateState(gfx::Point(), gfx::Vector2d(0, 10)).get());
@@ -641,9 +644,12 @@
   host_impl_->SetViewportSize(gfx::Size(50, 50));
   DrawFrame();
 
-  EXPECT_EQ(InputHandler::SCROLL_STARTED,
-            host_impl_->ScrollBegin(BeginState(gfx::Point()).get(),
-                                    InputHandler::WHEEL));
+  InputHandler::ScrollStatus status = host_impl_->ScrollBegin(
+      BeginState(gfx::Point()).get(), InputHandler::WHEEL);
+  EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, status.thread);
+  EXPECT_EQ(InputHandler::NOT_SCROLLING_ON_MAIN,
+            status.main_thread_scrolling_reasons);
+
   EXPECT_FALSE(host_impl_->IsActivelyScrolling());
   host_impl_->ScrollBy(UpdateState(gfx::Point(), gfx::Vector2d(0, 10)).get());
   EXPECT_TRUE(host_impl_->IsActivelyScrolling());
@@ -653,9 +659,11 @@
 
 TEST_F(LayerTreeHostImplTest, ScrollWithoutRootLayer) {
   // We should not crash when trying to scroll an empty layer tree.
-  EXPECT_EQ(InputHandler::SCROLL_IGNORED,
-            host_impl_->ScrollBegin(BeginState(gfx::Point()).get(),
-                                    InputHandler::WHEEL));
+  InputHandler::ScrollStatus status = host_impl_->ScrollBegin(
+      BeginState(gfx::Point()).get(), InputHandler::WHEEL);
+  EXPECT_EQ(InputHandler::SCROLL_IGNORED, status.thread);
+  EXPECT_EQ(InputHandler::NO_SCROLLING_LAYER,
+            status.main_thread_scrolling_reasons);
 }
 
 TEST_F(LayerTreeHostImplTest, ScrollWithoutRenderer) {
@@ -672,9 +680,11 @@
 
   // We should not crash when trying to scroll after the renderer initialization
   // fails.
-  EXPECT_EQ(InputHandler::SCROLL_STARTED,
-            host_impl_->ScrollBegin(BeginState(gfx::Point()).get(),
-                                    InputHandler::WHEEL));
+  InputHandler::ScrollStatus status = host_impl_->ScrollBegin(
+      BeginState(gfx::Point()).get(), InputHandler::WHEEL);
+  EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, status.thread);
+  EXPECT_EQ(InputHandler::NOT_SCROLLING_ON_MAIN,
+            status.main_thread_scrolling_reasons);
 }
 
 TEST_F(LayerTreeHostImplTest, ReplaceTreeWhileScrolling) {
@@ -683,9 +693,10 @@
   DrawFrame();
 
   // We should not crash if the tree is replaced while we are scrolling.
-  EXPECT_EQ(InputHandler::SCROLL_STARTED,
+  EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
             host_impl_->ScrollBegin(BeginState(gfx::Point()).get(),
-                                    InputHandler::WHEEL));
+                                    InputHandler::WHEEL)
+                .thread);
   host_impl_->active_tree()->DetachLayerTree();
 
   scroll_layer = SetupScrollAndContentsLayers(gfx::Size(100, 100));
@@ -709,30 +720,37 @@
   // With registered event handlers, wheel scrolls don't necessarily
   // have to go to the main thread.
   root->SetHaveWheelEventHandlers(true);
-  EXPECT_EQ(InputHandler::SCROLL_STARTED,
-            host_impl_->ScrollBegin(BeginState(gfx::Point()).get(),
-                                    InputHandler::WHEEL));
+  InputHandler::ScrollStatus status = host_impl_->ScrollBegin(
+      BeginState(gfx::Point()).get(), InputHandler::WHEEL);
+  EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, status.thread);
+  EXPECT_EQ(InputHandler::NOT_SCROLLING_ON_MAIN,
+            status.main_thread_scrolling_reasons);
   host_impl_->ScrollEnd(EndState().get());
 
   // But typically the scroll-blocks-on mode will require them to.
   root->SetScrollBlocksOn(SCROLL_BLOCKS_ON_WHEEL_EVENT |
                           SCROLL_BLOCKS_ON_START_TOUCH);
-  EXPECT_EQ(InputHandler::SCROLL_ON_MAIN_THREAD,
-            host_impl_->ScrollBegin(BeginState(gfx::Point()).get(),
-                                    InputHandler::WHEEL));
+  status = host_impl_->ScrollBegin(BeginState(gfx::Point()).get(),
+                                   InputHandler::WHEEL);
+  EXPECT_EQ(InputHandler::SCROLL_ON_MAIN_THREAD, status.thread);
+  EXPECT_EQ(InputHandler::EVENT_HANDLERS, status.main_thread_scrolling_reasons);
 
   // But gesture scrolls can still be handled.
-  EXPECT_EQ(InputHandler::SCROLL_STARTED,
-            host_impl_->ScrollBegin(BeginState(gfx::Point()).get(),
-                                    InputHandler::GESTURE));
+  status = host_impl_->ScrollBegin(BeginState(gfx::Point()).get(),
+                                   InputHandler::GESTURE);
+  EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, status.thread);
+  EXPECT_EQ(InputHandler::NOT_SCROLLING_ON_MAIN,
+            status.main_thread_scrolling_reasons);
   host_impl_->ScrollEnd(EndState().get());
 
   // And if the handlers go away, wheel scrolls can again be processed
   // on impl (despite the scroll-blocks-on mode).
   root->SetHaveWheelEventHandlers(false);
-  EXPECT_EQ(InputHandler::SCROLL_STARTED,
-            host_impl_->ScrollBegin(BeginState(gfx::Point()).get(),
-                                    InputHandler::WHEEL));
+  status = host_impl_->ScrollBegin(BeginState(gfx::Point()).get(),
+                                   InputHandler::WHEEL);
+  EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, status.thread);
+  EXPECT_EQ(InputHandler::NOT_SCROLLING_ON_MAIN,
+            status.main_thread_scrolling_reasons);
   host_impl_->ScrollEnd(EndState().get());
 }
 
@@ -762,9 +780,11 @@
   EXPECT_TRUE(host_impl_->DoTouchEventsBlockScrollAt(gfx::Point(10, 10)));
 
   // But they don't influence the actual handling of the scroll gestures.
-  EXPECT_EQ(InputHandler::SCROLL_STARTED,
-            host_impl_->ScrollBegin(BeginState(gfx::Point()).get(),
-                                    InputHandler::GESTURE));
+  InputHandler::ScrollStatus status = host_impl_->ScrollBegin(
+      BeginState(gfx::Point()).get(), InputHandler::GESTURE);
+  EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, status.thread);
+  EXPECT_EQ(InputHandler::NOT_SCROLLING_ON_MAIN,
+            status.main_thread_scrolling_reasons);
   host_impl_->ScrollEnd(EndState().get());
 
   // It's the union of scroll-blocks-on mode bits across all layers in the
@@ -785,36 +805,47 @@
   // With registered scroll handlers, scrolls don't generally have to go
   // to the main thread.
   root->SetHaveScrollEventHandlers(true);
-  EXPECT_EQ(InputHandler::SCROLL_STARTED,
-            host_impl_->ScrollBegin(BeginState(gfx::Point()).get(),
-                                    InputHandler::WHEEL));
+  InputHandler::ScrollStatus status = host_impl_->ScrollBegin(
+      BeginState(gfx::Point()).get(), InputHandler::WHEEL);
+  EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, status.thread);
+  EXPECT_EQ(InputHandler::NOT_SCROLLING_ON_MAIN,
+            status.main_thread_scrolling_reasons);
+
   host_impl_->ScrollEnd(EndState().get());
 
   // Even the default scroll blocks on mode doesn't require this.
   root->SetScrollBlocksOn(SCROLL_BLOCKS_ON_WHEEL_EVENT |
                           SCROLL_BLOCKS_ON_START_TOUCH);
-  EXPECT_EQ(InputHandler::SCROLL_STARTED,
-            host_impl_->ScrollBegin(BeginState(gfx::Point()).get(),
-                                    InputHandler::GESTURE));
+  status = host_impl_->ScrollBegin(BeginState(gfx::Point()).get(),
+                                   InputHandler::GESTURE);
+  EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, status.thread);
+  EXPECT_EQ(InputHandler::NOT_SCROLLING_ON_MAIN,
+            status.main_thread_scrolling_reasons);
+
   host_impl_->ScrollEnd(EndState().get());
 
   // But the page can opt in to blocking on scroll event handlers.
   root->SetScrollBlocksOn(SCROLL_BLOCKS_ON_SCROLL_EVENT);
-  EXPECT_EQ(InputHandler::SCROLL_ON_MAIN_THREAD,
-            host_impl_->ScrollBegin(BeginState(gfx::Point()).get(),
-                                    InputHandler::GESTURE));
+  status = host_impl_->ScrollBegin(BeginState(gfx::Point()).get(),
+                                   InputHandler::GESTURE);
+  EXPECT_EQ(InputHandler::SCROLL_ON_MAIN_THREAD, status.thread);
+  EXPECT_EQ(InputHandler::EVENT_HANDLERS, status.main_thread_scrolling_reasons);
 
   // GESTURE and WHEEL scrolls behave identically in this regard.
-  EXPECT_EQ(InputHandler::SCROLL_ON_MAIN_THREAD,
-            host_impl_->ScrollBegin(BeginState(gfx::Point()).get(),
-                                    InputHandler::WHEEL));
+  status = host_impl_->ScrollBegin(BeginState(gfx::Point()).get(),
+                                   InputHandler::WHEEL);
+  EXPECT_EQ(InputHandler::SCROLL_ON_MAIN_THREAD, status.thread);
+  EXPECT_EQ(InputHandler::EVENT_HANDLERS, status.main_thread_scrolling_reasons);
 
   // And if the handlers go away, scrolls can again be processed on impl
   // (despite the scroll-blocks-on mode).
   root->SetHaveScrollEventHandlers(false);
-  EXPECT_EQ(InputHandler::SCROLL_STARTED,
-            host_impl_->ScrollBegin(BeginState(gfx::Point()).get(),
-                                    InputHandler::GESTURE));
+  status = host_impl_->ScrollBegin(BeginState(gfx::Point()).get(),
+                                   InputHandler::GESTURE);
+  EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, status.thread);
+  EXPECT_EQ(InputHandler::NOT_SCROLLING_ON_MAIN,
+            status.main_thread_scrolling_reasons);
+
   host_impl_->ScrollEnd(EndState().get());
 }
 
@@ -858,46 +889,66 @@
     RebuildPropertyTrees();
   }
 
+  InputHandler::ScrollStatus status = host_impl_->ScrollBegin(
+      BeginState(gfx::Point(10, 10)).get(), InputHandler::GESTURE);
   // Scroll-blocks-on on a layer affects scrolls that hit that layer.
-  EXPECT_EQ(InputHandler::SCROLL_STARTED,
-            host_impl_->ScrollBegin(BeginState(gfx::Point(10, 10)).get(),
-                                    InputHandler::GESTURE));
+  EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, status.thread);
+  EXPECT_EQ(InputHandler::NOT_SCROLLING_ON_MAIN,
+            status.main_thread_scrolling_reasons);
   host_impl_->ScrollEnd(EndState().get());
+
   child1->SetScrollBlocksOn(SCROLL_BLOCKS_ON_SCROLL_EVENT);
-  EXPECT_EQ(InputHandler::SCROLL_ON_MAIN_THREAD,
-            host_impl_->ScrollBegin(BeginState(gfx::Point(10, 10)).get(),
-                                    InputHandler::GESTURE));
+  status = host_impl_->ScrollBegin(BeginState(gfx::Point(10, 10)).get(),
+                                   InputHandler::GESTURE);
+  EXPECT_EQ(InputHandler::SCROLL_ON_MAIN_THREAD, status.thread);
+  EXPECT_EQ(InputHandler::EVENT_HANDLERS, status.main_thread_scrolling_reasons);
 
   // But not those that hit only other layers.
-  EXPECT_EQ(InputHandler::SCROLL_STARTED,
-            host_impl_->ScrollBegin(BeginState(gfx::Point(10, 25)).get(),
-                                    InputHandler::GESTURE));
+  status = host_impl_->ScrollBegin(BeginState(gfx::Point(10, 25)).get(),
+                                   InputHandler::GESTURE);
+  EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, status.thread);
+  EXPECT_EQ(InputHandler::NOT_SCROLLING_ON_MAIN,
+            status.main_thread_scrolling_reasons);
   host_impl_->ScrollEnd(EndState().get());
 
   // It's the union of bits set across the scroll ancestor chain that matters.
-  EXPECT_EQ(InputHandler::SCROLL_STARTED,
-            host_impl_->ScrollBegin(BeginState(gfx::Point(10, 25)).get(),
-                                    InputHandler::GESTURE));
+  status = host_impl_->ScrollBegin(BeginState(gfx::Point(10, 25)).get(),
+                                   InputHandler::GESTURE);
+  EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, status.thread);
+  EXPECT_EQ(InputHandler::NOT_SCROLLING_ON_MAIN,
+            status.main_thread_scrolling_reasons);
+
   host_impl_->ScrollEnd(EndState().get());
-  EXPECT_EQ(InputHandler::SCROLL_STARTED,
-            host_impl_->ScrollBegin(BeginState(gfx::Point(10, 25)).get(),
-                                    InputHandler::WHEEL));
+  status = host_impl_->ScrollBegin(BeginState(gfx::Point(10, 25)).get(),
+                                   InputHandler::WHEEL);
+  EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, status.thread);
+  EXPECT_EQ(InputHandler::NOT_SCROLLING_ON_MAIN,
+            status.main_thread_scrolling_reasons);
+
   host_impl_->ScrollEnd(EndState().get());
   root->SetScrollBlocksOn(SCROLL_BLOCKS_ON_WHEEL_EVENT);
-  EXPECT_EQ(InputHandler::SCROLL_STARTED,
-            host_impl_->ScrollBegin(BeginState(gfx::Point(10, 25)).get(),
-                                    InputHandler::GESTURE));
+  status = host_impl_->ScrollBegin(BeginState(gfx::Point(10, 25)).get(),
+                                   InputHandler::GESTURE);
+  EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, status.thread);
+  EXPECT_EQ(InputHandler::NOT_SCROLLING_ON_MAIN,
+            status.main_thread_scrolling_reasons);
+
   host_impl_->ScrollEnd(EndState().get());
-  EXPECT_EQ(InputHandler::SCROLL_ON_MAIN_THREAD,
-            host_impl_->ScrollBegin(BeginState(gfx::Point(10, 25)).get(),
-                                    InputHandler::WHEEL));
+  status = host_impl_->ScrollBegin(BeginState(gfx::Point(10, 25)).get(),
+                                   InputHandler::WHEEL);
+  EXPECT_EQ(InputHandler::SCROLL_ON_MAIN_THREAD, status.thread);
+  EXPECT_EQ(InputHandler::EVENT_HANDLERS, status.main_thread_scrolling_reasons);
+
   child2->SetScrollBlocksOn(SCROLL_BLOCKS_ON_SCROLL_EVENT);
-  EXPECT_EQ(InputHandler::SCROLL_ON_MAIN_THREAD,
-            host_impl_->ScrollBegin(BeginState(gfx::Point(10, 25)).get(),
-                                    InputHandler::WHEEL));
-  EXPECT_EQ(InputHandler::SCROLL_ON_MAIN_THREAD,
-            host_impl_->ScrollBegin(BeginState(gfx::Point(10, 25)).get(),
-                                    InputHandler::GESTURE));
+  status = host_impl_->ScrollBegin(BeginState(gfx::Point(10, 25)).get(),
+                                   InputHandler::WHEEL);
+  EXPECT_EQ(InputHandler::SCROLL_ON_MAIN_THREAD, status.thread);
+  EXPECT_EQ(InputHandler::EVENT_HANDLERS, status.main_thread_scrolling_reasons);
+
+  status = host_impl_->ScrollBegin(BeginState(gfx::Point(10, 25)).get(),
+                                   InputHandler::GESTURE);
+  EXPECT_EQ(InputHandler::SCROLL_ON_MAIN_THREAD, status.thread);
+  EXPECT_EQ(InputHandler::EVENT_HANDLERS, status.main_thread_scrolling_reasons);
 }
 
 TEST_F(LayerTreeHostImplTest, FlingOnlyWhenScrollingTouchscreen) {
@@ -906,15 +957,23 @@
   DrawFrame();
 
   // Ignore the fling since no layer is being scrolled
-  EXPECT_EQ(InputHandler::SCROLL_IGNORED, host_impl_->FlingScrollBegin());
+  InputHandler::ScrollStatus status = host_impl_->FlingScrollBegin();
+  EXPECT_EQ(InputHandler::SCROLL_IGNORED, status.thread);
+  EXPECT_EQ(InputHandler::NO_SCROLLING_LAYER,
+            status.main_thread_scrolling_reasons);
 
   // Start scrolling a layer
-  EXPECT_EQ(InputHandler::SCROLL_STARTED,
-            host_impl_->ScrollBegin(BeginState(gfx::Point()).get(),
-                                    InputHandler::GESTURE));
+  status = host_impl_->ScrollBegin(BeginState(gfx::Point()).get(),
+                                   InputHandler::GESTURE);
+  EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, status.thread);
+  EXPECT_EQ(InputHandler::NOT_SCROLLING_ON_MAIN,
+            status.main_thread_scrolling_reasons);
 
   // Now the fling should go ahead since we've started scrolling a layer
-  EXPECT_EQ(InputHandler::SCROLL_STARTED, host_impl_->FlingScrollBegin());
+  status = host_impl_->FlingScrollBegin();
+  EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, status.thread);
+  EXPECT_EQ(InputHandler::NOT_SCROLLING_ON_MAIN,
+            status.main_thread_scrolling_reasons);
 }
 
 TEST_F(LayerTreeHostImplTest, FlingOnlyWhenScrollingTouchpad) {
@@ -923,15 +982,23 @@
   DrawFrame();
 
   // Ignore the fling since no layer is being scrolled
-  EXPECT_EQ(InputHandler::SCROLL_IGNORED, host_impl_->FlingScrollBegin());
+  InputHandler::ScrollStatus status = host_impl_->FlingScrollBegin();
+  EXPECT_EQ(InputHandler::SCROLL_IGNORED, status.thread);
+  EXPECT_EQ(InputHandler::NO_SCROLLING_LAYER,
+            status.main_thread_scrolling_reasons);
 
   // Start scrolling a layer
-  EXPECT_EQ(InputHandler::SCROLL_STARTED,
-            host_impl_->ScrollBegin(BeginState(gfx::Point()).get(),
-                                    InputHandler::WHEEL));
+  status = host_impl_->ScrollBegin(BeginState(gfx::Point()).get(),
+                                   InputHandler::WHEEL);
+  EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, status.thread);
+  EXPECT_EQ(InputHandler::NOT_SCROLLING_ON_MAIN,
+            status.main_thread_scrolling_reasons);
 
   // Now the fling should go ahead since we've started scrolling a layer
-  EXPECT_EQ(InputHandler::SCROLL_STARTED, host_impl_->FlingScrollBegin());
+  status = host_impl_->FlingScrollBegin();
+  EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, status.thread);
+  EXPECT_EQ(InputHandler::NOT_SCROLLING_ON_MAIN,
+            status.main_thread_scrolling_reasons);
 }
 
 TEST_F(LayerTreeHostImplTest, NoFlingWhenScrollingOnMain) {
@@ -940,15 +1007,21 @@
   DrawFrame();
   LayerImpl* root = host_impl_->active_tree()->root_layer();
 
-  root->SetShouldScrollOnMainThread(true);
+  root->set_main_thread_scrolling_reasons(
+      InputHandler::HAS_BACKGROUND_ATTACHMENT_FIXED_OBJECTS);
 
   // Start scrolling a layer
-  EXPECT_EQ(InputHandler::SCROLL_ON_MAIN_THREAD,
-            host_impl_->ScrollBegin(BeginState(gfx::Point()).get(),
-                                    InputHandler::GESTURE));
+  InputHandler::ScrollStatus status = host_impl_->ScrollBegin(
+      BeginState(gfx::Point()).get(), InputHandler::GESTURE);
+  EXPECT_EQ(InputHandler::SCROLL_ON_MAIN_THREAD, status.thread);
+  EXPECT_EQ(InputHandler::HAS_BACKGROUND_ATTACHMENT_FIXED_OBJECTS,
+            status.main_thread_scrolling_reasons);
 
   // The fling should be ignored since there's no layer being scrolled impl-side
-  EXPECT_EQ(InputHandler::SCROLL_IGNORED, host_impl_->FlingScrollBegin());
+  status = host_impl_->FlingScrollBegin();
+  EXPECT_EQ(InputHandler::SCROLL_IGNORED, status.thread);
+  EXPECT_EQ(InputHandler::NO_SCROLLING_LAYER,
+            status.main_thread_scrolling_reasons);
 }
 
 TEST_F(LayerTreeHostImplTest, ShouldScrollOnMainThread) {
@@ -957,14 +1030,20 @@
   DrawFrame();
   LayerImpl* root = host_impl_->active_tree()->root_layer();
 
-  root->SetShouldScrollOnMainThread(true);
+  root->set_main_thread_scrolling_reasons(
+      InputHandler::HAS_BACKGROUND_ATTACHMENT_FIXED_OBJECTS);
 
-  EXPECT_EQ(InputHandler::SCROLL_ON_MAIN_THREAD,
-            host_impl_->ScrollBegin(BeginState(gfx::Point()).get(),
-                                    InputHandler::WHEEL));
-  EXPECT_EQ(InputHandler::SCROLL_ON_MAIN_THREAD,
-            host_impl_->ScrollBegin(BeginState(gfx::Point()).get(),
-                                    InputHandler::GESTURE));
+  InputHandler::ScrollStatus status = host_impl_->ScrollBegin(
+      BeginState(gfx::Point()).get(), InputHandler::WHEEL);
+  EXPECT_EQ(InputHandler::SCROLL_ON_MAIN_THREAD, status.thread);
+  EXPECT_EQ(InputHandler::HAS_BACKGROUND_ATTACHMENT_FIXED_OBJECTS,
+            status.main_thread_scrolling_reasons);
+
+  status = host_impl_->ScrollBegin(BeginState(gfx::Point()).get(),
+                                   InputHandler::GESTURE);
+  EXPECT_EQ(InputHandler::SCROLL_ON_MAIN_THREAD, status.thread);
+  EXPECT_EQ(InputHandler::HAS_BACKGROUND_ATTACHMENT_FIXED_OBJECTS,
+            status.main_thread_scrolling_reasons);
 }
 
 TEST_F(LayerTreeHostImplTest, NonFastScrollableRegionBasic) {
@@ -977,21 +1056,29 @@
   DrawFrame();
 
   // All scroll types inside the non-fast scrollable region should fail.
-  EXPECT_EQ(InputHandler::SCROLL_ON_MAIN_THREAD,
-            host_impl_->ScrollBegin(BeginState(gfx::Point(25, 25)).get(),
-                                    InputHandler::WHEEL));
+  InputHandler::ScrollStatus status = host_impl_->ScrollBegin(
+      BeginState(gfx::Point(25, 25)).get(), InputHandler::WHEEL);
+  EXPECT_EQ(InputHandler::SCROLL_ON_MAIN_THREAD, status.thread);
+  EXPECT_EQ(InputHandler::NON_FAST_SCROLLABLE_REGION,
+            status.main_thread_scrolling_reasons);
   EXPECT_FALSE(host_impl_->IsCurrentlyScrollingLayerAt(gfx::Point(25, 25),
                                                        InputHandler::WHEEL));
-  EXPECT_EQ(InputHandler::SCROLL_ON_MAIN_THREAD,
-            host_impl_->ScrollBegin(BeginState(gfx::Point(25, 25)).get(),
-                                    InputHandler::GESTURE));
+
+  status = host_impl_->ScrollBegin(BeginState(gfx::Point(25, 25)).get(),
+                                   InputHandler::GESTURE);
+  EXPECT_EQ(InputHandler::SCROLL_ON_MAIN_THREAD, status.thread);
+  EXPECT_EQ(InputHandler::NON_FAST_SCROLLABLE_REGION,
+            status.main_thread_scrolling_reasons);
   EXPECT_FALSE(host_impl_->IsCurrentlyScrollingLayerAt(gfx::Point(25, 25),
                                                        InputHandler::GESTURE));
 
   // All scroll types outside this region should succeed.
-  EXPECT_EQ(InputHandler::SCROLL_STARTED,
-            host_impl_->ScrollBegin(BeginState(gfx::Point(75, 75)).get(),
-                                    InputHandler::WHEEL));
+  status = host_impl_->ScrollBegin(BeginState(gfx::Point(75, 75)).get(),
+                                   InputHandler::WHEEL);
+  EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, status.thread);
+  EXPECT_EQ(InputHandler::NOT_SCROLLING_ON_MAIN,
+            status.main_thread_scrolling_reasons);
+
   EXPECT_TRUE(host_impl_->IsCurrentlyScrollingLayerAt(gfx::Point(75, 75),
                                                       InputHandler::GESTURE));
   host_impl_->ScrollBy(UpdateState(gfx::Point(), gfx::Vector2d(0, 10)).get());
@@ -1000,9 +1087,12 @@
   host_impl_->ScrollEnd(EndState().get());
   EXPECT_FALSE(host_impl_->IsCurrentlyScrollingLayerAt(gfx::Point(75, 75),
                                                        InputHandler::GESTURE));
-  EXPECT_EQ(InputHandler::SCROLL_STARTED,
-            host_impl_->ScrollBegin(BeginState(gfx::Point(75, 75)).get(),
-                                    InputHandler::GESTURE));
+
+  status = host_impl_->ScrollBegin(BeginState(gfx::Point(75, 75)).get(),
+                                   InputHandler::GESTURE);
+  EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, status.thread);
+  EXPECT_EQ(InputHandler::NOT_SCROLLING_ON_MAIN,
+            status.main_thread_scrolling_reasons);
   EXPECT_TRUE(host_impl_->IsCurrentlyScrollingLayerAt(gfx::Point(75, 75),
                                                       InputHandler::GESTURE));
   host_impl_->ScrollBy(UpdateState(gfx::Point(), gfx::Vector2d(0, 10)).get());
@@ -1024,18 +1114,23 @@
 
   // This point would fall into the non-fast scrollable region except that we've
   // moved the layer down by 25 pixels.
-  EXPECT_EQ(InputHandler::SCROLL_STARTED,
-            host_impl_->ScrollBegin(BeginState(gfx::Point(40, 10)).get(),
-                                    InputHandler::WHEEL));
+  InputHandler::ScrollStatus status = host_impl_->ScrollBegin(
+      BeginState(gfx::Point(40, 10)).get(), InputHandler::WHEEL);
+  EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, status.thread);
+  EXPECT_EQ(InputHandler::NOT_SCROLLING_ON_MAIN,
+            status.main_thread_scrolling_reasons);
+
   EXPECT_TRUE(host_impl_->IsCurrentlyScrollingLayerAt(gfx::Point(40, 10),
                                                       InputHandler::WHEEL));
   host_impl_->ScrollBy(UpdateState(gfx::Point(), gfx::Vector2d(0, 1)).get());
   host_impl_->ScrollEnd(EndState().get());
 
   // This point is still inside the non-fast region.
-  EXPECT_EQ(InputHandler::SCROLL_ON_MAIN_THREAD,
-            host_impl_->ScrollBegin(BeginState(gfx::Point(10, 10)).get(),
-                                    InputHandler::WHEEL));
+  status = host_impl_->ScrollBegin(BeginState(gfx::Point(10, 10)).get(),
+                                   InputHandler::WHEEL);
+  EXPECT_EQ(InputHandler::SCROLL_ON_MAIN_THREAD, status.thread);
+  EXPECT_EQ(InputHandler::NON_FAST_SCROLLABLE_REGION,
+            status.main_thread_scrolling_reasons);
 }
 
 TEST_F(LayerTreeHostImplTest, ScrollHandlerNotPresent) {
@@ -1072,9 +1167,11 @@
 
   DrawFrame();
 
-  EXPECT_EQ(InputHandler::SCROLL_STARTED,
-            host_impl_->ScrollBegin(BeginState(gfx::Point()).get(),
-                                    InputHandler::GESTURE));
+  InputHandler::ScrollStatus status = host_impl_->ScrollBegin(
+      BeginState(gfx::Point()).get(), InputHandler::GESTURE);
+  EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, status.thread);
+  EXPECT_EQ(InputHandler::NOT_SCROLLING_ON_MAIN,
+            status.main_thread_scrolling_reasons);
 
   // Trying to scroll to the left/top will not succeed.
   EXPECT_FALSE(
@@ -1145,9 +1242,10 @@
 
   DrawFrame();
 
-  EXPECT_EQ(InputHandler::SCROLL_STARTED,
+  EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
             host_impl_->ScrollBegin(BeginState(gfx::Point()).get(),
-                                    InputHandler::WHEEL));
+                                    InputHandler::WHEEL)
+                .thread);
 
   // Trying to scroll if not user_scrollable_vertical will fail.
   host_impl_->InnerViewportScrollLayer()->set_user_scrollable_vertical(false);
@@ -1180,9 +1278,10 @@
   DrawFrame();
   gfx::Point scroll_position(10, 10);
 
-  EXPECT_EQ(InputHandler::SCROLL_STARTED,
+  EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
             host_impl_->ScrollBegin(BeginState(scroll_position).get(),
-                                    InputHandler::WHEEL));
+                                    InputHandler::WHEEL)
+                .thread);
   EXPECT_VECTOR_EQ(gfx::Vector2dF(), scroll_layer->CurrentScrollOffset());
   EXPECT_VECTOR_EQ(gfx::Vector2dF(), overflow->CurrentScrollOffset());
 
@@ -1194,9 +1293,10 @@
 
   overflow->set_user_scrollable_horizontal(false);
 
-  EXPECT_EQ(InputHandler::SCROLL_STARTED,
+  EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
             host_impl_->ScrollBegin(BeginState(scroll_position).get(),
-                                    InputHandler::WHEEL));
+                                    InputHandler::WHEEL)
+                .thread);
   EXPECT_VECTOR_EQ(gfx::Vector2dF(), scroll_layer->CurrentScrollOffset());
   EXPECT_VECTOR_EQ(gfx::Vector2dF(10, 10), overflow->CurrentScrollOffset());
 
@@ -1207,9 +1307,10 @@
 
   overflow->set_user_scrollable_vertical(false);
 
-  EXPECT_EQ(InputHandler::SCROLL_STARTED,
+  EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
             host_impl_->ScrollBegin(BeginState(scroll_position).get(),
-                                    InputHandler::WHEEL));
+                                    InputHandler::WHEEL)
+                .thread);
   EXPECT_VECTOR_EQ(gfx::Vector2dF(0, 0), scroll_layer->CurrentScrollOffset());
   EXPECT_VECTOR_EQ(gfx::Vector2dF(10, 20), overflow->CurrentScrollOffset());
 
@@ -1556,9 +1657,10 @@
     host_impl_->ScrollEnd(EndState().get());
 
     gfx::Vector2d scroll_delta(0, 10);
-    EXPECT_EQ(InputHandler::SCROLL_STARTED,
+    EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
               host_impl_->ScrollBegin(BeginState(gfx::Point(5, 5)).get(),
-                                      InputHandler::WHEEL));
+                                      InputHandler::WHEEL)
+                  .thread);
     host_impl_->ScrollBy(UpdateState(gfx::Point(), scroll_delta).get());
     host_impl_->ScrollEnd(EndState().get());
 
@@ -1907,9 +2009,10 @@
       new LatencyInfoSwapPromise(latency_info));
 
   SetupScrollAndContentsLayers(gfx::Size(100, 100));
-  EXPECT_EQ(InputHandler::SCROLL_STARTED,
+  EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
             host_impl_->ScrollBegin(BeginState(gfx::Point()).get(),
-                                    InputHandler::GESTURE));
+                                    InputHandler::GESTURE)
+                .thread);
   host_impl_->ScrollBy(UpdateState(gfx::Point(), gfx::Vector2d(0, 10)).get());
   host_impl_->QueueSwapPromiseForMainThreadScrollUpdate(
       std::move(swap_promise));
@@ -3036,9 +3139,10 @@
   }
 
   // Scrolling should update metadata immediately.
-  EXPECT_EQ(InputHandler::SCROLL_STARTED,
+  EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
             host_impl_->ScrollBegin(BeginState(gfx::Point()).get(),
-                                    InputHandler::WHEEL));
+                                    InputHandler::WHEEL)
+                .thread);
   host_impl_->ScrollBy(UpdateState(gfx::Point(), gfx::Vector2d(0, 10)).get());
   {
     CompositorFrameMetadata metadata =
@@ -3669,9 +3773,11 @@
   DrawFrame();
 
   // Scroll event is ignored because layer is not scrollable.
-  EXPECT_EQ(InputHandler::SCROLL_IGNORED,
-            host_impl_->ScrollBegin(BeginState(gfx::Point()).get(),
-                                    InputHandler::WHEEL));
+  InputHandler::ScrollStatus status = host_impl_->ScrollBegin(
+      BeginState(gfx::Point()).get(), InputHandler::WHEEL);
+  EXPECT_EQ(InputHandler::SCROLL_IGNORED, status.thread);
+  EXPECT_EQ(InputHandler::NO_SCROLLING_LAYER,
+            status.main_thread_scrolling_reasons);
   EXPECT_FALSE(did_request_redraw_);
   EXPECT_FALSE(did_request_commit_);
 }
@@ -3817,9 +3923,10 @@
 
   EXPECT_EQ(gfx::SizeF(50, 50), active_tree->ScrollableSize());
 
-  EXPECT_EQ(InputHandler::SCROLL_STARTED,
+  EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
             host_impl_->ScrollBegin(BeginState(gfx::Point()).get(),
-                                    InputHandler::GESTURE));
+                                    InputHandler::GESTURE)
+                .thread);
 
   host_impl_->top_controls_manager()->ScrollBegin();
 
@@ -3860,9 +3967,10 @@
       gfx::Size(10, 10), gfx::Size(10, 10), gfx::Size(10, 10));
   DrawFrame();
 
-  EXPECT_EQ(InputHandler::SCROLL_STARTED,
+  EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
             host_impl_->ScrollBegin(BeginState(gfx::Point()).get(),
-                                    InputHandler::GESTURE));
+                                    InputHandler::GESTURE)
+                .thread);
 
   // Make the test scroll delta a fractional amount, to verify that the
   // fixed container size delta is (1) non-zero, and (2) fractional, and
@@ -3904,9 +4012,10 @@
   outer_scroll->SetDrawsContent(true);
   host_impl_->active_tree()->PushPageScaleFromMainThread(2.f, 1.f, 2.f);
 
-  EXPECT_EQ(InputHandler::SCROLL_STARTED,
+  EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
             host_impl_->ScrollBegin(BeginState(gfx::Point()).get(),
-                                    InputHandler::GESTURE));
+                                    InputHandler::GESTURE)
+                .thread);
   host_impl_->ScrollBy(
       UpdateState(gfx::Point(), gfx::Vector2dF(0.f, 50.f)).get());
 
@@ -3926,9 +4035,10 @@
 
   host_impl_->ScrollEnd(EndState().get());
 
-  EXPECT_EQ(InputHandler::SCROLL_STARTED,
+  EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
             host_impl_->ScrollBegin(BeginState(gfx::Point()).get(),
-                                    InputHandler::GESTURE));
+                                    InputHandler::GESTURE)
+                .thread);
   EXPECT_EQ(host_impl_->CurrentlyScrollingLayer(), inner_scroll);
 
   host_impl_->ScrollBy(
@@ -3979,9 +4089,10 @@
   // not be scaled.
   host_impl_->active_tree()->PushPageScaleFromMainThread(page_scale, 1.f, 2.f);
 
-  EXPECT_EQ(InputHandler::SCROLL_STARTED,
+  EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
             host_impl_->ScrollBegin(BeginState(gfx::Point()).get(),
-                                    InputHandler::GESTURE));
+                                    InputHandler::GESTURE)
+                .thread);
 
   // Scroll down, the top controls hiding should expand the viewport size so
   // the delta should be equal to the scroll distance.
@@ -4028,9 +4139,10 @@
 
   // Scroll 25px to hide top controls
   gfx::Vector2dF scroll_delta(0.f, 25.f);
-  EXPECT_EQ(InputHandler::SCROLL_STARTED,
+  EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
             host_impl_->ScrollBegin(BeginState(gfx::Point()).get(),
-                                    InputHandler::GESTURE));
+                                    InputHandler::GESTURE)
+                .thread);
   host_impl_->ScrollBy(UpdateState(gfx::Point(), scroll_delta).get());
   EXPECT_FALSE(did_request_commit_);
 }
@@ -4072,9 +4184,10 @@
   gfx::Vector2dF scroll_delta(0.f, 25.f);
   host_impl_->active_tree()->property_trees()->needs_rebuild = true;
   host_impl_->active_tree()->BuildPropertyTreesForTesting();
-  EXPECT_EQ(InputHandler::SCROLL_STARTED,
+  EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
             host_impl_->ScrollBegin(BeginState(gfx::Point()).get(),
-                                    InputHandler::GESTURE));
+                                    InputHandler::GESTURE)
+                .thread);
   host_impl_->ScrollBy(UpdateState(gfx::Point(), scroll_delta).get());
   host_impl_->ScrollEnd(EndState().get());
 
@@ -4232,9 +4345,10 @@
 
   // Hide the top controls by 25px.
   gfx::Vector2dF scroll_delta(0.f, 25.f);
-  EXPECT_EQ(InputHandler::SCROLL_STARTED,
+  EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
             host_impl_->ScrollBegin(BeginState(gfx::Point()).get(),
-                                    InputHandler::GESTURE));
+                                    InputHandler::GESTURE)
+                .thread);
   host_impl_->ScrollBy(UpdateState(gfx::Point(), scroll_delta).get());
 
   // scrolling down at the max extents no longer hides the top controls
@@ -4259,9 +4373,10 @@
 
   // Bring the top controls down by 25px.
   scroll_delta = gfx::Vector2dF(0.f, -25.f);
-  EXPECT_EQ(InputHandler::SCROLL_STARTED,
+  EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
             host_impl_->ScrollBegin(BeginState(gfx::Point()).get(),
-                                    InputHandler::GESTURE));
+                                    InputHandler::GESTURE)
+                .thread);
   host_impl_->ScrollBy(UpdateState(gfx::Point(), scroll_delta).get());
   host_impl_->ScrollEnd(EndState().get());
 
@@ -4288,9 +4403,10 @@
                   host_impl_->top_controls_manager()->ContentTopOffset());
 
   gfx::Vector2dF scroll_delta(0.f, 25.f);
-  EXPECT_EQ(InputHandler::SCROLL_STARTED,
+  EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
             host_impl_->ScrollBegin(BeginState(gfx::Point()).get(),
-                                    InputHandler::GESTURE));
+                                    InputHandler::GESTURE)
+                .thread);
   host_impl_->ScrollBy(UpdateState(gfx::Point(), scroll_delta).get());
   host_impl_->ScrollEnd(EndState().get());
 
@@ -4329,9 +4445,10 @@
   // Send a gesture scroll that will scroll the outer viewport, make sure the
   // top controls get scrolled.
   gfx::Vector2dF scroll_delta(0.f, 15.f);
-  EXPECT_EQ(InputHandler::SCROLL_STARTED,
+  EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
             host_impl_->ScrollBegin(BeginState(gfx::Point()).get(),
-                                    InputHandler::GESTURE));
+                                    InputHandler::GESTURE)
+                .thread);
   host_impl_->ScrollBy(UpdateState(gfx::Point(), scroll_delta).get());
 
   EXPECT_EQ(host_impl_->InnerViewportScrollLayer(),
@@ -4343,9 +4460,10 @@
                       host_impl_->top_controls_manager()->ContentTopOffset());
 
   scroll_delta = gfx::Vector2dF(0.f, 50.f);
-  EXPECT_EQ(InputHandler::SCROLL_STARTED,
+  EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
             host_impl_->ScrollBegin(BeginState(gfx::Point()).get(),
-                                    InputHandler::GESTURE));
+                                    InputHandler::GESTURE)
+                .thread);
   host_impl_->ScrollBy(UpdateState(gfx::Point(), scroll_delta).get());
 
   EXPECT_EQ(0, host_impl_->top_controls_manager()->ContentTopOffset());
@@ -4360,9 +4478,10 @@
   host_impl_->InnerViewportScrollLayer()->SetScrollDelta(inner_viewport_offset);
 
   scroll_delta = gfx::Vector2dF(0.f, -65.f);
-  EXPECT_EQ(InputHandler::SCROLL_STARTED,
+  EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
             host_impl_->ScrollBegin(BeginState(gfx::Point()).get(),
-                                    InputHandler::GESTURE));
+                                    InputHandler::GESTURE)
+                .thread);
   host_impl_->ScrollBy(UpdateState(gfx::Point(), scroll_delta).get());
 
   EXPECT_EQ(top_controls_height_,
@@ -4382,9 +4501,10 @@
       layer_size_, layer_size_, layer_size_);
   DrawFrame();
 
-  EXPECT_EQ(InputHandler::SCROLL_STARTED,
+  EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
             host_impl_->ScrollBegin(BeginState(gfx::Point()).get(),
-                                    InputHandler::GESTURE));
+                                    InputHandler::GESTURE)
+                .thread);
 
   host_impl_->top_controls_manager()->ScrollBegin();
   host_impl_->top_controls_manager()->ScrollBy(gfx::Vector2dF(0.f, 50.f));
@@ -4397,9 +4517,10 @@
 
   host_impl_->ScrollEnd(EndState().get());
 
-  EXPECT_EQ(InputHandler::SCROLL_STARTED,
+  EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
             host_impl_->ScrollBegin(BeginState(gfx::Point()).get(),
-                                    InputHandler::GESTURE));
+                                    InputHandler::GESTURE)
+                .thread);
 
   float scroll_increment_y = -25.f;
   host_impl_->top_controls_manager()->ScrollBegin();
@@ -4427,9 +4548,10 @@
       gfx::ScrollOffset(),
       host_impl_->active_tree()->InnerViewportScrollLayer()->MaxScrollOffset());
 
-  EXPECT_EQ(InputHandler::SCROLL_STARTED,
+  EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
             host_impl_->ScrollBegin(BeginState(gfx::Point()).get(),
-                                    InputHandler::GESTURE));
+                                    InputHandler::GESTURE)
+                .thread);
 }
 
 TEST_F(LayerTreeHostImplTest, ScrollNonCompositedRoot) {
@@ -4461,9 +4583,10 @@
   host_impl_->SetViewportSize(surface_size);
   DrawFrame();
 
-  EXPECT_EQ(InputHandler::SCROLL_STARTED,
+  EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
             host_impl_->ScrollBegin(BeginState(gfx::Point(5, 5)).get(),
-                                    InputHandler::WHEEL));
+                                    InputHandler::WHEEL)
+                .thread);
   host_impl_->ScrollBy(UpdateState(gfx::Point(), gfx::Vector2d(0, 10)).get());
   host_impl_->ScrollEnd(EndState().get());
   EXPECT_TRUE(did_request_redraw_);
@@ -4481,9 +4604,10 @@
   host_impl_->SetViewportSize(surface_size);
   DrawFrame();
 
-  EXPECT_EQ(InputHandler::SCROLL_STARTED,
+  EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
             host_impl_->ScrollBegin(BeginState(gfx::Point(5, 5)).get(),
-                                    InputHandler::WHEEL));
+                                    InputHandler::WHEEL)
+                .thread);
   host_impl_->ScrollBy(UpdateState(gfx::Point(), gfx::Vector2d(0, 10)).get());
   host_impl_->ScrollEnd(EndState().get());
   EXPECT_TRUE(did_request_redraw_);
@@ -4501,9 +4625,12 @@
 
   // Scroll event is ignored because the input coordinate is outside the layer
   // boundaries.
-  EXPECT_EQ(InputHandler::SCROLL_IGNORED,
-            host_impl_->ScrollBegin(BeginState(gfx::Point(15, 5)).get(),
-                                    InputHandler::WHEEL));
+  InputHandler::ScrollStatus status = host_impl_->ScrollBegin(
+      BeginState(gfx::Point(15, 5)).get(), InputHandler::WHEEL);
+  EXPECT_EQ(InputHandler::SCROLL_IGNORED, status.thread);
+  EXPECT_EQ(InputHandler::NO_SCROLLING_LAYER,
+            status.main_thread_scrolling_reasons);
+
   EXPECT_FALSE(did_request_redraw_);
   EXPECT_FALSE(did_request_commit_);
 }
@@ -4527,9 +4654,12 @@
 
   // Scroll event is ignored because the scrollable layer is not facing the
   // viewer and there is nothing scrollable behind it.
-  EXPECT_EQ(InputHandler::SCROLL_IGNORED,
-            host_impl_->ScrollBegin(BeginState(gfx::Point(5, 5)).get(),
-                                    InputHandler::WHEEL));
+  InputHandler::ScrollStatus status = host_impl_->ScrollBegin(
+      BeginState(gfx::Point(5, 5)).get(), InputHandler::WHEEL);
+  EXPECT_EQ(InputHandler::SCROLL_IGNORED, status.thread);
+  EXPECT_EQ(InputHandler::NO_SCROLLING_LAYER,
+            status.main_thread_scrolling_reasons);
+
   EXPECT_FALSE(did_request_redraw_);
   EXPECT_FALSE(did_request_commit_);
 }
@@ -4540,7 +4670,8 @@
       LayerImpl::Create(host_impl_->active_tree(), 3);
   scoped_ptr<LayerImpl> content_layer =
       CreateScrollableLayer(1, surface_size, clip_layer.get());
-  content_layer->SetShouldScrollOnMainThread(true);
+  content_layer->set_main_thread_scrolling_reasons(
+      InputHandler::HAS_BACKGROUND_ATTACHMENT_FIXED_OBJECTS);
   content_layer->SetScrollClipLayer(Layer::INVALID_ID);
 
   // Note: we can use the same clip layer for both since both calls to
@@ -4557,9 +4688,11 @@
 
   // Scrolling fails because the content layer is asking to be scrolled on the
   // main thread.
-  EXPECT_EQ(InputHandler::SCROLL_ON_MAIN_THREAD,
-            host_impl_->ScrollBegin(BeginState(gfx::Point(5, 5)).get(),
-                                    InputHandler::WHEEL));
+  InputHandler::ScrollStatus status = host_impl_->ScrollBegin(
+      BeginState(gfx::Point(5, 5)).get(), InputHandler::WHEEL);
+  EXPECT_EQ(InputHandler::SCROLL_ON_MAIN_THREAD, status.thread);
+  EXPECT_EQ(InputHandler::HAS_BACKGROUND_ATTACHMENT_FIXED_OBJECTS,
+            status.main_thread_scrolling_reasons);
 }
 
 TEST_F(LayerTreeHostImplTest, ScrollRootAndChangePageScaleOnMainThread) {
@@ -4585,9 +4718,10 @@
   gfx::Vector2d scroll_delta(0, 10);
   gfx::Vector2d expected_scroll_delta = scroll_delta;
   gfx::ScrollOffset expected_max_scroll = root_scroll->MaxScrollOffset();
-  EXPECT_EQ(InputHandler::SCROLL_STARTED,
+  EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
             host_impl_->ScrollBegin(BeginState(gfx::Point(5, 5)).get(),
-                                    InputHandler::WHEEL));
+                                    InputHandler::WHEEL)
+                .thread);
   host_impl_->ScrollBy(UpdateState(gfx::Point(), scroll_delta).get());
   host_impl_->ScrollEnd(EndState().get());
 
@@ -4629,9 +4763,10 @@
   gfx::Vector2d scroll_delta(0, 10);
   gfx::Vector2d expected_scroll_delta = scroll_delta;
   gfx::ScrollOffset expected_max_scroll = root_scroll->MaxScrollOffset();
-  EXPECT_EQ(InputHandler::SCROLL_STARTED,
+  EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
             host_impl_->ScrollBegin(BeginState(gfx::Point(5, 5)).get(),
-                                    InputHandler::WHEEL));
+                                    InputHandler::WHEEL)
+                .thread);
   host_impl_->ScrollBy(UpdateState(gfx::Point(), scroll_delta).get());
   host_impl_->ScrollEnd(EndState().get());
 
@@ -4726,9 +4861,10 @@
   gfx::Vector2d scroll_delta(0, 10);
   gfx::Vector2d expected_scroll_delta(scroll_delta);
   gfx::ScrollOffset expected_max_scroll(outer_scroll->MaxScrollOffset());
-  EXPECT_EQ(InputHandler::SCROLL_STARTED,
+  EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
             host_impl_->ScrollBegin(BeginState(gfx::Point(5, 5)).get(),
-                                    InputHandler::WHEEL));
+                                    InputHandler::WHEEL)
+                .thread);
   host_impl_->ScrollBy(UpdateState(gfx::Point(), scroll_delta).get());
   host_impl_->ScrollEnd(EndState().get());
 
@@ -4777,9 +4913,10 @@
   DrawFrame();
   {
     gfx::Vector2d scroll_delta(-8, -7);
-    EXPECT_EQ(InputHandler::SCROLL_STARTED,
+    EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
               host_impl_->ScrollBegin(BeginState(gfx::Point()).get(),
-                                      InputHandler::WHEEL));
+                                      InputHandler::WHEEL)
+                  .thread);
     host_impl_->ScrollBy(UpdateState(gfx::Point(), scroll_delta).get());
     host_impl_->ScrollEnd(EndState().get());
 
@@ -4837,9 +4974,10 @@
   DrawFrame();
   {
     gfx::Vector2d scroll_delta(0, -10);
-    EXPECT_EQ(InputHandler::SCROLL_STARTED,
+    EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
               host_impl_->ScrollBegin(BeginState(gfx::Point()).get(),
-                                      InputHandler::NON_BUBBLING_GESTURE));
+                                      InputHandler::NON_BUBBLING_GESTURE)
+                  .thread);
     host_impl_->ScrollBy(UpdateState(gfx::Point(), scroll_delta).get());
     host_impl_->ScrollEnd(EndState().get());
 
@@ -4862,9 +5000,10 @@
 
     // The next time we scroll we should only scroll the parent.
     scroll_delta = gfx::Vector2d(0, -3);
-    EXPECT_EQ(InputHandler::SCROLL_STARTED,
+    EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
               host_impl_->ScrollBegin(BeginState(gfx::Point(5, 5)).get(),
-                                      InputHandler::NON_BUBBLING_GESTURE));
+                                      InputHandler::NON_BUBBLING_GESTURE)
+                  .thread);
     EXPECT_EQ(host_impl_->CurrentlyScrollingLayer(), grand_child);
     host_impl_->ScrollBy(UpdateState(gfx::Point(), scroll_delta).get());
     EXPECT_EQ(host_impl_->CurrentlyScrollingLayer(), child);
@@ -4883,9 +5022,10 @@
     // After scrolling the parent, another scroll on the opposite direction
     // should still scroll the child.
     scroll_delta = gfx::Vector2d(0, 7);
-    EXPECT_EQ(InputHandler::SCROLL_STARTED,
+    EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
               host_impl_->ScrollBegin(BeginState(gfx::Point(5, 5)).get(),
-                                      InputHandler::NON_BUBBLING_GESTURE));
+                                      InputHandler::NON_BUBBLING_GESTURE)
+                  .thread);
     EXPECT_EQ(host_impl_->CurrentlyScrollingLayer(), grand_child);
     host_impl_->ScrollBy(UpdateState(gfx::Point(), scroll_delta).get());
     EXPECT_EQ(host_impl_->CurrentlyScrollingLayer(), grand_child);
@@ -4906,9 +5046,10 @@
     host_impl_->active_tree()->SetPageScaleOnActiveTree(2.f);
 
     scroll_delta = gfx::Vector2d(0, -2);
-    EXPECT_EQ(InputHandler::SCROLL_STARTED,
+    EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
               host_impl_->ScrollBegin(BeginState(gfx::Point(1, 1)).get(),
-                                      InputHandler::NON_BUBBLING_GESTURE));
+                                      InputHandler::NON_BUBBLING_GESTURE)
+                  .thread);
     EXPECT_EQ(grand_child, host_impl_->CurrentlyScrollingLayer());
     host_impl_->ScrollBy(UpdateState(gfx::Point(), scroll_delta).get());
     host_impl_->ScrollEnd(EndState().get());
@@ -4952,9 +5093,10 @@
   DrawFrame();
   {
     gfx::Vector2d scroll_delta(0, 4);
-    EXPECT_EQ(InputHandler::SCROLL_STARTED,
+    EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
               host_impl_->ScrollBegin(BeginState(gfx::Point(5, 5)).get(),
-                                      InputHandler::WHEEL));
+                                      InputHandler::WHEEL)
+                  .thread);
     host_impl_->ScrollBy(UpdateState(gfx::Point(), scroll_delta).get());
     host_impl_->ScrollEnd(EndState().get());
 
@@ -5007,9 +5149,10 @@
 
   // Scrolling should still work even though we did not draw yet.
   RebuildPropertyTrees();
-  EXPECT_EQ(InputHandler::SCROLL_STARTED,
+  EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
             host_impl_->ScrollBegin(BeginState(gfx::Point(5, 5)).get(),
-                                    InputHandler::WHEEL));
+                                    InputHandler::WHEEL)
+                .thread);
 }
 
 TEST_F(LayerTreeHostImplTest, ScrollAxisAlignedRotatedLayer) {
@@ -5027,9 +5170,10 @@
 
   // Scroll to the right in screen coordinates with a gesture.
   gfx::Vector2d gesture_scroll_delta(10, 0);
-  EXPECT_EQ(InputHandler::SCROLL_STARTED,
+  EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
             host_impl_->ScrollBegin(BeginState(gfx::Point()).get(),
-                                    InputHandler::GESTURE));
+                                    InputHandler::GESTURE)
+                .thread);
   host_impl_->ScrollBy(UpdateState(gfx::Point(), gesture_scroll_delta).get());
   host_impl_->ScrollEnd(EndState().get());
 
@@ -5041,9 +5185,10 @@
   // Reset and scroll down with the wheel.
   scroll_layer->SetScrollDelta(gfx::Vector2dF());
   gfx::Vector2d wheel_scroll_delta(0, 10);
-  EXPECT_EQ(InputHandler::SCROLL_STARTED,
+  EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
             host_impl_->ScrollBegin(BeginState(gfx::Point()).get(),
-                                    InputHandler::WHEEL));
+                                    InputHandler::WHEEL)
+                .thread);
   host_impl_->ScrollBy(UpdateState(gfx::Point(), wheel_scroll_delta).get());
   host_impl_->ScrollEnd(EndState().get());
 
@@ -5088,9 +5233,10 @@
   {
     // Scroll down in screen coordinates with a gesture.
     gfx::Vector2d gesture_scroll_delta(0, 10);
-    EXPECT_EQ(InputHandler::SCROLL_STARTED,
+    EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
               host_impl_->ScrollBegin(BeginState(gfx::Point(1, 1)).get(),
-                                      InputHandler::GESTURE));
+                                      InputHandler::GESTURE)
+                  .thread);
     host_impl_->ScrollBy(UpdateState(gfx::Point(), gesture_scroll_delta).get());
     host_impl_->ScrollEnd(EndState().get());
 
@@ -5112,9 +5258,10 @@
     // Now reset and scroll the same amount horizontally.
     child_ptr->SetScrollDelta(gfx::Vector2dF());
     gfx::Vector2d gesture_scroll_delta(10, 0);
-    EXPECT_EQ(InputHandler::SCROLL_STARTED,
+    EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
               host_impl_->ScrollBegin(BeginState(gfx::Point(1, 1)).get(),
-                                      InputHandler::GESTURE));
+                                      InputHandler::GESTURE)
+                  .thread);
     host_impl_->ScrollBy(UpdateState(gfx::Point(), gesture_scroll_delta).get());
     host_impl_->ScrollEnd(EndState().get());
 
@@ -5191,9 +5338,10 @@
   for (int i = 0; i < 4; ++i) {
     child_ptr->SetScrollDelta(gfx::Vector2dF());
     DrawFrame();
-    EXPECT_EQ(InputHandler::SCROLL_STARTED,
+    EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
               host_impl_->ScrollBegin(BeginState(viewport_point).get(),
-                                      InputHandler::GESTURE));
+                                      InputHandler::GESTURE)
+                  .thread);
     host_impl_->ScrollBy(
         UpdateState(viewport_point, gesture_scroll_deltas[i]).get());
     viewport_point += gesture_scroll_deltas[i];
@@ -5225,9 +5373,10 @@
 
   // Scroll down in screen coordinates with a gesture.
   gfx::Vector2d scroll_delta(0, 10);
-  EXPECT_EQ(InputHandler::SCROLL_STARTED,
+  EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
             host_impl_->ScrollBegin(BeginState(gfx::Point()).get(),
-                                    InputHandler::GESTURE));
+                                    InputHandler::GESTURE)
+                .thread);
   host_impl_->ScrollBy(UpdateState(gfx::Point(), scroll_delta).get());
   host_impl_->ScrollEnd(EndState().get());
 
@@ -5240,9 +5389,10 @@
   // Reset and scroll down with the wheel.
   scroll_layer->SetScrollDelta(gfx::Vector2dF());
   gfx::Vector2d wheel_scroll_delta(0, 10);
-  EXPECT_EQ(InputHandler::SCROLL_STARTED,
+  EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
             host_impl_->ScrollBegin(BeginState(gfx::Point()).get(),
-                                    InputHandler::WHEEL));
+                                    InputHandler::WHEEL)
+                .thread);
   host_impl_->ScrollBy(UpdateState(gfx::Point(), wheel_scroll_delta).get());
   host_impl_->ScrollEnd(EndState().get());
 
@@ -5394,9 +5544,10 @@
   gfx::Vector2dF scroll_delta(0.f, 10.f);
   gfx::ScrollOffset current_offset(7.f, 8.f);
 
-  EXPECT_EQ(InputHandler::SCROLL_STARTED,
+  EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
             host_impl_->ScrollBegin(BeginState(gfx::Point()).get(),
-                                    InputHandler::GESTURE));
+                                    InputHandler::GESTURE)
+                .thread);
   host_impl_->SetSynchronousInputHandlerRootScrollOffset(current_offset);
 
   host_impl_->ScrollBy(UpdateState(gfx::Point(), scroll_delta).get());
@@ -5470,9 +5621,10 @@
   EXPECT_EQ(gfx::Vector2dF(), host_impl_->accumulated_root_overscroll());
 
   // In-bounds scrolling does not affect overscroll.
-  EXPECT_EQ(InputHandler::SCROLL_STARTED,
+  EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
             host_impl_->ScrollBegin(BeginState(gfx::Point()).get(),
-                                    InputHandler::WHEEL));
+                                    InputHandler::WHEEL)
+                .thread);
   scroll_result = host_impl_->ScrollBy(
       UpdateState(gfx::Point(), gfx::Vector2d(0, 10)).get());
   EXPECT_TRUE(scroll_result.did_scroll);
@@ -5619,9 +5771,10 @@
   DrawFrame();
   {
     gfx::Vector2d scroll_delta(0, -10);
-    EXPECT_EQ(InputHandler::SCROLL_STARTED,
+    EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
               host_impl_->ScrollBegin(BeginState(gfx::Point()).get(),
-                                      InputHandler::NON_BUBBLING_GESTURE));
+                                      InputHandler::NON_BUBBLING_GESTURE)
+                  .thread);
     scroll_result =
         host_impl_->ScrollBy(UpdateState(gfx::Point(), scroll_delta).get());
     EXPECT_TRUE(scroll_result.did_scroll);
@@ -5632,9 +5785,10 @@
     // The next time we scroll we should only scroll the parent, but overscroll
     // should still not reach the root layer.
     scroll_delta = gfx::Vector2d(0, -30);
-    EXPECT_EQ(InputHandler::SCROLL_STARTED,
+    EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
               host_impl_->ScrollBegin(BeginState(gfx::Point(5, 5)).get(),
-                                      InputHandler::NON_BUBBLING_GESTURE));
+                                      InputHandler::NON_BUBBLING_GESTURE)
+                  .thread);
     EXPECT_EQ(host_impl_->CurrentlyScrollingLayer(), grand_child_layer);
     EXPECT_EQ(gfx::Vector2dF(), host_impl_->accumulated_root_overscroll());
     scroll_result =
@@ -5648,9 +5802,10 @@
     // After scrolling the parent, another scroll on the opposite direction
     // should scroll the child.
     scroll_delta = gfx::Vector2d(0, 70);
-    EXPECT_EQ(InputHandler::SCROLL_STARTED,
+    EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
               host_impl_->ScrollBegin(BeginState(gfx::Point(5, 5)).get(),
-                                      InputHandler::NON_BUBBLING_GESTURE));
+                                      InputHandler::NON_BUBBLING_GESTURE)
+                  .thread);
     EXPECT_EQ(host_impl_->CurrentlyScrollingLayer(), grand_child_layer);
     scroll_result =
         host_impl_->ScrollBy(UpdateState(gfx::Point(), scroll_delta).get());
@@ -5671,9 +5826,10 @@
   DrawFrame();
   {
     gfx::Vector2d scroll_delta(0, 8);
-    EXPECT_EQ(InputHandler::SCROLL_STARTED,
+    EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
               host_impl_->ScrollBegin(BeginState(gfx::Point(5, 5)).get(),
-                                      InputHandler::WHEEL));
+                                      InputHandler::WHEEL)
+                  .thread);
     scroll_result =
         host_impl_->ScrollBy(UpdateState(gfx::Point(), scroll_delta).get());
     EXPECT_TRUE(scroll_result.did_scroll);
@@ -5707,9 +5863,10 @@
   EXPECT_EQ(gfx::Vector2dF(), host_impl_->accumulated_root_overscroll());
 
   // Even though the layer can't scroll the overscroll still happens.
-  EXPECT_EQ(InputHandler::SCROLL_STARTED,
+  EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
             host_impl_->ScrollBegin(BeginState(gfx::Point()).get(),
-                                    InputHandler::WHEEL));
+                                    InputHandler::WHEEL)
+                .thread);
   scroll_result = host_impl_->ScrollBy(
       UpdateState(gfx::Point(), gfx::Vector2d(0, 10)).get());
   EXPECT_FALSE(scroll_result.did_scroll);
@@ -5726,9 +5883,10 @@
     // Edge glow effect should be applicable only upon reaching Edges
     // of the content. unnecessary glow effect calls shouldn't be
     // called while scrolling up without reaching the edge of the content.
-    EXPECT_EQ(InputHandler::SCROLL_STARTED,
+    EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
               host_impl_->ScrollBegin(BeginState(gfx::Point(0, 0)).get(),
-                                      InputHandler::WHEEL));
+                                      InputHandler::WHEEL)
+                  .thread);
     scroll_result = host_impl_->ScrollBy(
         UpdateState(gfx::Point(), gfx::Vector2dF(0, 100)).get());
     EXPECT_TRUE(scroll_result.did_scroll);
@@ -5744,10 +5902,12 @@
     host_impl_->ScrollEnd(EndState().get());
     // unusedrootDelta should be subtracted from applied delta so that
     // unwanted glow effect calls are not called.
-    EXPECT_EQ(InputHandler::SCROLL_STARTED,
-              host_impl_->ScrollBegin(BeginState(gfx::Point()).get(),
-                                      InputHandler::NON_BUBBLING_GESTURE));
-    EXPECT_EQ(InputHandler::SCROLL_STARTED, host_impl_->FlingScrollBegin());
+    EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
+              host_impl_->ScrollBegin(BeginState(gfx::Point(0, 0)).get(),
+                                      InputHandler::NON_BUBBLING_GESTURE)
+                  .thread);
+    EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
+              host_impl_->FlingScrollBegin().thread);
     scroll_result = host_impl_->ScrollBy(
         UpdateState(gfx::Point(), gfx::Vector2dF(0, 20)).get());
     EXPECT_TRUE(scroll_result.did_scroll);
@@ -5764,9 +5924,10 @@
     host_impl_->ScrollEnd(EndState().get());
     // TestCase to check  kEpsilon, which prevents minute values to trigger
     // gloweffect without reaching edge.
-    EXPECT_EQ(InputHandler::SCROLL_STARTED,
+    EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
               host_impl_->ScrollBegin(BeginState(gfx::Point(0, 0)).get(),
-                                      InputHandler::WHEEL));
+                                      InputHandler::WHEEL)
+                  .thread);
     scroll_result = host_impl_->ScrollBy(
         UpdateState(gfx::Point(), gfx::Vector2dF(-0.12f, 0.1f)).get());
     EXPECT_FALSE(scroll_result.did_scroll);
@@ -7460,11 +7621,13 @@
   host_impl_->active_tree()->DidBecomeActive();
   DrawFrame();
   {
-    EXPECT_EQ(InputHandler::SCROLL_STARTED,
+    EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
               host_impl_->ScrollBegin(BeginState(gfx::Point()).get(),
-                                      InputHandler::GESTURE));
+                                      InputHandler::GESTURE)
+                  .thread);
 
-    EXPECT_EQ(InputHandler::SCROLL_STARTED, host_impl_->FlingScrollBegin());
+    EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
+              host_impl_->FlingScrollBegin().thread);
 
     gfx::Vector2d scroll_delta(0, 100);
     host_impl_->ScrollBy(UpdateState(gfx::Point(), scroll_delta).get());
@@ -7513,9 +7676,10 @@
     LayerImpl* grand_child = child->children()[0].get();
 
     gfx::Vector2d scroll_delta(0, -2);
-    EXPECT_EQ(InputHandler::SCROLL_STARTED,
+    EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
               host_impl_->ScrollBegin(BeginState(gfx::Point()).get(),
-                                      InputHandler::GESTURE));
+                                      InputHandler::GESTURE)
+                  .thread);
     EXPECT_TRUE(
         host_impl_->ScrollBy(UpdateState(gfx::Point(), scroll_delta).get())
             .did_scroll);
@@ -7538,7 +7702,8 @@
     ExpectNone(*scroll_info, child->id());
     EXPECT_EQ(host_impl_->CurrentlyScrollingLayer(), grand_child);
 
-    EXPECT_EQ(InputHandler::SCROLL_STARTED, host_impl_->FlingScrollBegin());
+    EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
+              host_impl_->FlingScrollBegin().thread);
     EXPECT_FALSE(
         host_impl_->ScrollBy(UpdateState(gfx::Point(), scroll_delta).get())
             .did_scroll);
@@ -7581,11 +7746,13 @@
   host_impl_->active_tree()->DidBecomeActive();
   DrawFrame();
   {
-    EXPECT_EQ(InputHandler::SCROLL_STARTED,
+    EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
               host_impl_->ScrollBegin(BeginState(gfx::Point()).get(),
-                                      InputHandler::WHEEL));
+                                      InputHandler::WHEEL)
+                  .thread);
 
-    EXPECT_EQ(InputHandler::SCROLL_STARTED, host_impl_->FlingScrollBegin());
+    EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
+              host_impl_->FlingScrollBegin().thread);
 
     gfx::Vector2d scroll_delta(0, 100);
     host_impl_->ScrollBy(UpdateState(gfx::Point(), scroll_delta).get());
@@ -7629,9 +7796,11 @@
 
   DrawFrame();
 
-  EXPECT_EQ(InputHandler::SCROLL_UNKNOWN,
-            host_impl_->ScrollBegin(BeginState(gfx::Point()).get(),
-                                    InputHandler::WHEEL));
+  InputHandler::ScrollStatus status = host_impl_->ScrollBegin(
+      BeginState(gfx::Point()).get(), InputHandler::WHEEL);
+  EXPECT_EQ(InputHandler::SCROLL_UNKNOWN, status.thread);
+  EXPECT_EQ(InputHandler::FAILED_HIT_TEST,
+            status.main_thread_scrolling_reasons);
 }
 
 TEST_F(LayerTreeHostImplTest, ScrollUnknownScrollAncestorMismatch) {
@@ -7668,9 +7837,11 @@
 
   DrawFrame();
 
-  EXPECT_EQ(InputHandler::SCROLL_UNKNOWN,
-            host_impl_->ScrollBegin(BeginState(gfx::Point()).get(),
-                                    InputHandler::WHEEL));
+  InputHandler::ScrollStatus status = host_impl_->ScrollBegin(
+      BeginState(gfx::Point()).get(), InputHandler::WHEEL);
+  EXPECT_EQ(InputHandler::SCROLL_UNKNOWN, status.thread);
+  EXPECT_EQ(InputHandler::FAILED_HIT_TEST,
+            status.main_thread_scrolling_reasons);
 }
 
 TEST_F(LayerTreeHostImplTest, NotScrollInvisibleScroller) {
@@ -7698,9 +7869,10 @@
   //
   // Why SCROLL_STARTED? In this case, it's because we've bubbled out and
   // started scrolling the inner viewport.
-  EXPECT_EQ(InputHandler::SCROLL_STARTED,
+  EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
             host_impl_->ScrollBegin(BeginState(gfx::Point()).get(),
-                                    InputHandler::WHEEL));
+                                    InputHandler::WHEEL)
+                .thread);
 
   EXPECT_EQ(2, host_impl_->CurrentlyScrollingLayer()->id());
 }
@@ -7735,9 +7907,10 @@
 
   // We should have scrolled |invisible_scroll_layer| as it was hit and it has
   // a descendant which is a drawn RSLL member.
-  EXPECT_EQ(InputHandler::SCROLL_STARTED,
+  EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
             host_impl_->ScrollBegin(BeginState(gfx::Point()).get(),
-                                    InputHandler::WHEEL));
+                                    InputHandler::WHEEL)
+                .thread);
 
   EXPECT_EQ(7, host_impl_->CurrentlyScrollingLayer()->id());
 }
@@ -7789,9 +7962,10 @@
   // We should have scrolled |child_scroll| even though it is invisible.
   // The reason for this is that if the scrolling the scroll would move a layer
   // that is a drawn RSLL member, then we should accept this hit.
-  EXPECT_EQ(InputHandler::SCROLL_STARTED,
+  EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
             host_impl_->ScrollBegin(BeginState(gfx::Point()).get(),
-                                    InputHandler::WHEEL));
+                                    InputHandler::WHEEL)
+                .thread);
 
   EXPECT_EQ(7, host_impl_->CurrentlyScrollingLayer()->id());
 }
@@ -7981,9 +8155,10 @@
     LayerImpl* scroll_layer = SetupScrollAndContentsLayers(gfx::Size(100, 100));
 
     // Scrolling normally should not trigger any forwarding.
-    EXPECT_EQ(InputHandler::SCROLL_STARTED,
+    EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
               host_impl_->ScrollBegin(BeginState(gfx::Point()).get(),
-                                      InputHandler::GESTURE));
+                                      InputHandler::GESTURE)
+                  .thread);
     EXPECT_TRUE(
         host_impl_->ScrollBy(
                       UpdateState(gfx::Point(), gfx::Vector2d(0, 10)).get())
@@ -7997,9 +8172,10 @@
     // Scrolling with a scroll handler should defer the swap to the main
     // thread.
     scroll_layer->SetHaveScrollEventHandlers(true);
-    EXPECT_EQ(InputHandler::SCROLL_STARTED,
+    EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
               host_impl_->ScrollBegin(BeginState(gfx::Point()).get(),
-                                      InputHandler::GESTURE));
+                                      InputHandler::GESTURE)
+                  .thread);
     EXPECT_TRUE(
         host_impl_->ScrollBy(
                       UpdateState(gfx::Point(), gfx::Vector2d(0, 10)).get())
@@ -8080,9 +8256,10 @@
       BOTH, SHOWN, false);
   DrawFrame();
 
-  EXPECT_EQ(InputHandler::SCROLL_STARTED,
+  EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
             host_impl_->ScrollBegin(BeginState(gfx::Point()).get(),
-                                    InputHandler::GESTURE));
+                                    InputHandler::GESTURE)
+                .thread);
   EXPECT_EQ(0, host_impl_->top_controls_manager()->ControlsTopOffset());
   EXPECT_EQ(gfx::Vector2dF().ToString(),
             scroll_layer->CurrentScrollOffset().ToString());
@@ -8154,9 +8331,10 @@
 
   LayerImpl* viewport_layer = host_impl_->InnerViewportScrollLayer();
 
-  EXPECT_EQ(InputHandler::SCROLL_STARTED,
+  EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
             host_impl_->ScrollBegin(BeginState(gfx::Point()).get(),
-                                    InputHandler::WHEEL));
+                                    InputHandler::WHEEL)
+                .thread);
   EXPECT_EQ(0, host_impl_->top_controls_manager()->ControlsTopOffset());
   EXPECT_VECTOR_EQ(gfx::Vector2dF(), viewport_layer->CurrentScrollOffset());
 
@@ -8187,9 +8365,10 @@
       BOTH, SHOWN, false);
   DrawFrame();
 
-  EXPECT_EQ(InputHandler::SCROLL_STARTED,
+  EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
             host_impl_->ScrollBegin(BeginState(gfx::Point()).get(),
-                                    InputHandler::GESTURE));
+                                    InputHandler::GESTURE)
+                .thread);
   EXPECT_EQ(0, host_impl_->top_controls_manager()->ControlsTopOffset());
   EXPECT_EQ(gfx::Vector2dF().ToString(),
             scroll_layer->CurrentScrollOffset().ToString());
@@ -8264,9 +8443,10 @@
       gfx::ScrollOffset(0, initial_scroll_offset));
   DrawFrame();
 
-  EXPECT_EQ(InputHandler::SCROLL_STARTED,
+  EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
             host_impl_->ScrollBegin(BeginState(gfx::Point()).get(),
-                                    InputHandler::GESTURE));
+                                    InputHandler::GESTURE)
+                .thread);
   EXPECT_EQ(0, host_impl_->top_controls_manager()->ControlsTopOffset());
   EXPECT_EQ(gfx::Vector2dF(0, initial_scroll_offset).ToString(),
             scroll_layer->CurrentScrollOffset().ToString());
@@ -8334,9 +8514,10 @@
       gfx::ScrollOffset(0, initial_scroll_offset));
   DrawFrame();
 
-  EXPECT_EQ(InputHandler::SCROLL_STARTED,
+  EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
             host_impl_->ScrollBegin(BeginState(gfx::Point()).get(),
-                                    InputHandler::GESTURE));
+                                    InputHandler::GESTURE)
+                .thread);
   EXPECT_EQ(0, host_impl_->top_controls_manager()->ControlsTopOffset());
   EXPECT_EQ(gfx::Vector2dF(0, initial_scroll_offset).ToString(),
             scroll_layer->CurrentScrollOffset().ToString());
@@ -8402,9 +8583,10 @@
                                                              false);
   DrawFrame();
 
-  EXPECT_EQ(InputHandler::SCROLL_STARTED,
+  EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
             host_impl_->ScrollBegin(BeginState(gfx::Point()).get(),
-                                    InputHandler::GESTURE));
+                                    InputHandler::GESTURE)
+                .thread);
   EXPECT_EQ(0, host_impl_->top_controls_manager()->ControlsTopOffset());
 
   float offset = 50;
@@ -8577,11 +8759,13 @@
 
     // Scrolling the viewport always sets the outer scroll layer as the
     // currently scrolling layer.
-    EXPECT_EQ(InputHandler::SCROLL_STARTED,
+    EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
               host_impl_->ScrollBegin(BeginState(gfx::Point()).get(),
-                                      InputHandler::GESTURE));
+                                      InputHandler::GESTURE)
+                  .thread);
     EXPECT_EQ(inner_scroll, host_impl_->CurrentlyScrollingLayer());
-    EXPECT_EQ(InputHandler::SCROLL_STARTED, host_impl_->FlingScrollBegin());
+    EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
+              host_impl_->FlingScrollBegin().thread);
     EXPECT_EQ(inner_scroll, host_impl_->CurrentlyScrollingLayer());
 
     gfx::Vector2d scroll_delta(inner_viewport.width() / 2.f,
@@ -8597,11 +8781,13 @@
     EXPECT_VECTOR_EQ(outer_expected, outer_scroll->CurrentScrollOffset());
 
     // Fling past the inner viewport boundry, make sure outer viewport scrolls.
-    EXPECT_EQ(InputHandler::SCROLL_STARTED,
+    EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
               host_impl_->ScrollBegin(BeginState(gfx::Point()).get(),
-                                      InputHandler::GESTURE));
+                                      InputHandler::GESTURE)
+                  .thread);
     EXPECT_EQ(inner_scroll, host_impl_->CurrentlyScrollingLayer());
-    EXPECT_EQ(InputHandler::SCROLL_STARTED, host_impl_->FlingScrollBegin());
+    EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
+              host_impl_->FlingScrollBegin().thread);
     EXPECT_EQ(inner_scroll, host_impl_->CurrentlyScrollingLayer());
 
     host_impl_->ScrollBy(UpdateState(gfx::Point(), scroll_delta).get());
@@ -8638,10 +8824,12 @@
     EXPECT_VECTOR_EQ(outer_expected, outer_scroll->CurrentScrollOffset());
 
     // Make sure the scroll goes to the inner viewport first.
-    EXPECT_EQ(InputHandler::SCROLL_STARTED,
+    EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
               host_impl_->ScrollBegin(BeginState(gfx::Point()).get(),
-                                      InputHandler::GESTURE));
-    EXPECT_EQ(InputHandler::SCROLL_STARTED, host_impl_->FlingScrollBegin());
+                                      InputHandler::GESTURE)
+                  .thread);
+    EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
+              host_impl_->FlingScrollBegin().thread);
     EXPECT_TRUE(host_impl_->IsCurrentlyScrollingLayerAt(gfx::Point(),
                                                         InputHandler::GESTURE));
 
@@ -8695,9 +8883,10 @@
     scoped_ptr<ScrollAndScaleSet> scroll_info;
 
     gfx::Vector2d scroll_delta(0, inner_viewport.height());
-    EXPECT_EQ(InputHandler::SCROLL_STARTED,
+    EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
               host_impl_->ScrollBegin(BeginState(gfx::Point()).get(),
-                                      InputHandler::GESTURE));
+                                      InputHandler::GESTURE)
+                  .thread);
     EXPECT_TRUE(
         host_impl_->ScrollBy(UpdateState(gfx::Point(), scroll_delta).get())
             .did_scroll);
@@ -8712,7 +8901,8 @@
     EXPECT_EQ(host_impl_->CurrentlyScrollingLayer(), child_scroll);
 
     // The fling have no effect on the currently scrolling layer.
-    EXPECT_EQ(InputHandler::SCROLL_STARTED, host_impl_->FlingScrollBegin());
+    EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
+              host_impl_->FlingScrollBegin().thread);
     EXPECT_FALSE(
         host_impl_->ScrollBy(UpdateState(gfx::Point(), scroll_delta).get())
             .did_scroll);
@@ -8756,14 +8946,16 @@
 
   DrawFrame();
 
-  EXPECT_EQ(InputHandler::SCROLL_STARTED,
+  EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
             host_impl_->RootScrollBegin(BeginState(gfx::Point()).get(),
-                                        InputHandler::GESTURE));
+                                        InputHandler::GESTURE)
+                .thread);
   EXPECT_EQ(host_impl_->CurrentlyScrollingLayer(), inner_scroll);
   host_impl_->ScrollEnd(EndState().get());
-  EXPECT_EQ(InputHandler::SCROLL_STARTED,
+  EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
             host_impl_->ScrollBegin(BeginState(gfx::Point()).get(),
-                                    InputHandler::GESTURE));
+                                    InputHandler::GESTURE)
+                .thread);
   EXPECT_EQ(host_impl_->CurrentlyScrollingLayer(), child_scroll);
   host_impl_->ScrollEnd(EndState().get());
 }
@@ -8784,9 +8976,10 @@
 
   // Ensure inner viewport doesn't react to scrolls (test it's unscrollable).
   EXPECT_VECTOR_EQ(gfx::Vector2dF(), inner_scroll->CurrentScrollOffset());
-  EXPECT_EQ(InputHandler::SCROLL_STARTED,
+  EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
             host_impl_->ScrollBegin(BeginState(gfx::Point()).get(),
-                                    InputHandler::GESTURE));
+                                    InputHandler::GESTURE)
+                .thread);
   scroll_result = host_impl_->ScrollBy(
       UpdateState(gfx::Point(), gfx::Vector2dF(0, 100)).get());
   EXPECT_VECTOR_EQ(gfx::Vector2dF(), inner_scroll->CurrentScrollOffset());
@@ -9089,8 +9282,9 @@
   BeginFrameArgs begin_frame_args =
       CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE);
 
-  EXPECT_EQ(InputHandler::SCROLL_STARTED,
-            host_impl_->ScrollAnimated(gfx::Point(), gfx::Vector2d(0, 50)));
+  EXPECT_EQ(
+      InputHandler::SCROLL_ON_IMPL_THREAD,
+      host_impl_->ScrollAnimated(gfx::Point(), gfx::Vector2d(0, 50)).thread);
 
   LayerImpl* scrolling_layer = host_impl_->CurrentlyScrollingLayer();
   EXPECT_EQ(host_impl_->OuterViewportScrollLayer(), scrolling_layer);
@@ -9113,8 +9307,9 @@
   EXPECT_TRUE(y > 1 && y < 49);
 
   // Update target.
-  EXPECT_EQ(InputHandler::SCROLL_STARTED,
-            host_impl_->ScrollAnimated(gfx::Point(), gfx::Vector2d(0, 50)));
+  EXPECT_EQ(
+      InputHandler::SCROLL_ON_IMPL_THREAD,
+      host_impl_->ScrollAnimated(gfx::Point(), gfx::Vector2d(0, 50)).thread);
   host_impl_->DidFinishImplFrame();
 
   begin_frame_args.frame_time =
@@ -9153,8 +9348,9 @@
       CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE);
 
   // Perform animated scroll.
-  EXPECT_EQ(InputHandler::SCROLL_STARTED,
-            host_impl_->ScrollAnimated(gfx::Point(), gfx::Vector2d(0, 50)));
+  EXPECT_EQ(
+      InputHandler::SCROLL_ON_IMPL_THREAD,
+      host_impl_->ScrollAnimated(gfx::Point(), gfx::Vector2d(0, 50)).thread);
 
   LayerImpl* scrolling_layer = host_impl_->CurrentlyScrollingLayer();
 
@@ -9179,9 +9375,10 @@
   EXPECT_TRUE(y > 1 && y < 49);
 
   // Perform instant scroll.
-  EXPECT_EQ(InputHandler::SCROLL_STARTED,
+  EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
             host_impl_->ScrollBegin(BeginState(gfx::Point(0, y)).get(),
-                                    InputHandler::WHEEL));
+                                    InputHandler::WHEEL)
+                .thread);
   EXPECT_TRUE(host_impl_->IsCurrentlyScrollingLayerAt(gfx::Point(0, y),
                                                       InputHandler::WHEEL));
   host_impl_->ScrollBy(
@@ -9217,8 +9414,9 @@
   BeginFrameArgs begin_frame_args =
       CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE);
 
-  EXPECT_EQ(InputHandler::SCROLL_STARTED,
-            host_impl_->ScrollAnimated(gfx::Point(), gfx::Vector2d(0, 50)));
+  EXPECT_EQ(
+      InputHandler::SCROLL_ON_IMPL_THREAD,
+      host_impl_->ScrollAnimated(gfx::Point(), gfx::Vector2d(0, 50)).thread);
 
   LayerImpl* scrolling_layer = host_impl_->CurrentlyScrollingLayer();
 
@@ -9240,8 +9438,9 @@
   EXPECT_TRUE(y > 1 && y < 49);
 
   // Update target.
-  EXPECT_EQ(InputHandler::SCROLL_STARTED,
-            host_impl_->ScrollAnimated(gfx::Point(), gfx::Vector2d(0, 50)));
+  EXPECT_EQ(
+      InputHandler::SCROLL_ON_IMPL_THREAD,
+      host_impl_->ScrollAnimated(gfx::Point(), gfx::Vector2d(0, 50)).thread);
   host_impl_->DidFinishImplFrame();
 
   begin_frame_args.frame_time =
@@ -9379,9 +9578,10 @@
     host_impl_->ScrollEnd(EndState().get());
 
     gfx::Vector2dF scroll_delta(0, 5);
-    EXPECT_EQ(InputHandler::SCROLL_STARTED,
+    EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
               host_impl_->ScrollBegin(BeginState(gfx::Point()).get(),
-                                      InputHandler::WHEEL));
+                                      InputHandler::WHEEL)
+                  .thread);
     EXPECT_VECTOR_EQ(gfx::Vector2dF(), scroll_layer->CurrentScrollOffset());
 
     host_impl_->ScrollBy(UpdateState(gfx::Point(), scroll_delta).get());
diff --git a/cc/trees/layer_tree_host_unittest_scroll.cc b/cc/trees/layer_tree_host_unittest_scroll.cc
index ac20d47f..6d34140 100644
--- a/cc/trees/layer_tree_host_unittest_scroll.cc
+++ b/cc/trees/layer_tree_host_unittest_scroll.cc
@@ -608,7 +608,7 @@
                                gfx::Vector2dF(0.5f, 0.5f));
         InputHandler::ScrollStatus status = impl->ScrollBegin(
             BeginState(scroll_point).get(), InputHandler::GESTURE);
-        EXPECT_EQ(InputHandler::SCROLL_STARTED, status);
+        EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, status.thread);
         impl->ScrollBy(UpdateState(gfx::Point(), scroll_amount_).get());
         LayerImpl* scrolling_layer = impl->CurrentlyScrollingLayer();
         CHECK(scrolling_layer);
@@ -631,7 +631,7 @@
                                gfx::Vector2dF(0.5f, 0.5f));
         InputHandler::ScrollStatus status = impl->ScrollBegin(
             BeginState(scroll_point).get(), InputHandler::WHEEL);
-        EXPECT_EQ(InputHandler::SCROLL_STARTED, status);
+        EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, status.thread);
         impl->ScrollBy(UpdateState(gfx::Point(), scroll_amount_).get());
         impl->ScrollEnd(EndState().get());
 
@@ -1034,24 +1034,29 @@
     // Set max_scroll_offset = (100, 100).
     scroll_layer->SetBounds(
         gfx::Size(root->bounds().width() + 100, root->bounds().height() + 100));
-    EXPECT_EQ(
-        InputHandler::SCROLL_STARTED,
-        scroll_layer->TryScroll(gfx::PointF(0.0f, 1.0f), InputHandler::GESTURE,
-                                SCROLL_BLOCKS_ON_NONE));
+
+    InputHandler::ScrollStatus status = scroll_layer->TryScroll(
+        gfx::PointF(0.0f, 1.0f), InputHandler::GESTURE, SCROLL_BLOCKS_ON_NONE);
+
+    EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, status.thread);
+    EXPECT_EQ(InputHandler::NOT_SCROLLING_ON_MAIN,
+              status.main_thread_scrolling_reasons);
 
     // Set max_scroll_offset = (0, 0).
     scroll_layer->SetBounds(root->bounds());
-    EXPECT_EQ(
-        InputHandler::SCROLL_IGNORED,
-        scroll_layer->TryScroll(gfx::PointF(0.0f, 1.0f), InputHandler::GESTURE,
-                                SCROLL_BLOCKS_ON_NONE));
+    status = scroll_layer->TryScroll(
+        gfx::PointF(0.0f, 1.0f), InputHandler::GESTURE, SCROLL_BLOCKS_ON_NONE);
+    EXPECT_EQ(InputHandler::SCROLL_IGNORED, status.thread);
+    EXPECT_EQ(InputHandler::NOT_SCROLLABLE,
+              status.main_thread_scrolling_reasons);
 
     // Set max_scroll_offset = (-100, -100).
     scroll_layer->SetBounds(gfx::Size());
-    EXPECT_EQ(
-        InputHandler::SCROLL_IGNORED,
-        scroll_layer->TryScroll(gfx::PointF(0.0f, 1.0f), InputHandler::GESTURE,
-                                SCROLL_BLOCKS_ON_NONE));
+    status = scroll_layer->TryScroll(
+        gfx::PointF(0.0f, 1.0f), InputHandler::GESTURE, SCROLL_BLOCKS_ON_NONE);
+    EXPECT_EQ(InputHandler::SCROLL_IGNORED, status.thread);
+    EXPECT_EQ(InputHandler::NOT_SCROLLABLE,
+              status.main_thread_scrolling_reasons);
 
     EndTest();
   }
@@ -1085,14 +1090,18 @@
     // Verify that the scroll layer's scroll offset is taken into account when
     // checking whether the screen space point is inside the non-fast
     // scrollable region.
-    EXPECT_EQ(
-        InputHandler::SCROLL_ON_MAIN_THREAD,
-        scroll_layer->TryScroll(gfx::PointF(1.f, 1.f), InputHandler::GESTURE,
-                                SCROLL_BLOCKS_ON_NONE));
-    EXPECT_EQ(
-        InputHandler::SCROLL_STARTED,
-        scroll_layer->TryScroll(gfx::PointF(21.f, 21.f), InputHandler::GESTURE,
-                                SCROLL_BLOCKS_ON_NONE));
+
+    InputHandler::ScrollStatus status = scroll_layer->TryScroll(
+        gfx::PointF(1.f, 1.f), InputHandler::GESTURE, SCROLL_BLOCKS_ON_NONE);
+    EXPECT_EQ(InputHandler::SCROLL_ON_MAIN_THREAD, status.thread);
+    EXPECT_EQ(InputHandler::NON_FAST_SCROLLABLE_REGION,
+              status.main_thread_scrolling_reasons);
+
+    status = scroll_layer->TryScroll(
+        gfx::PointF(21.f, 21.f), InputHandler::GESTURE, SCROLL_BLOCKS_ON_NONE);
+    EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, status.thread);
+    EXPECT_EQ(InputHandler::NOT_SCROLLING_ON_MAIN,
+              status.main_thread_scrolling_reasons);
 
     EndTest();
   }
diff --git a/chrome/android/java/AndroidManifest.xml b/chrome/android/java/AndroidManifest.xml
index 73d3dbe..b21f383 100644
--- a/chrome/android/java/AndroidManifest.xml
+++ b/chrome/android/java/AndroidManifest.xml
@@ -642,7 +642,8 @@
             android:exported="false" />
         {% endfor %}
 
-        <receiver android:name="org.chromium.chrome.browser.download.OpenDownloadReceiver">
+        <receiver android:name="org.chromium.chrome.browser.download.DownloadBroadcastReceiver"
+            android:exported="false">
             <intent-filter>
                 <action android:name="android.intent.action.DOWNLOAD_NOTIFICATION_CLICKED"/>
             </intent-filter>
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/DeferredStartupHandler.java b/chrome/android/java/src/org/chromium/chrome/browser/DeferredStartupHandler.java
index ac8e02b..79976e2 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/DeferredStartupHandler.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/DeferredStartupHandler.java
@@ -17,7 +17,6 @@
 import org.chromium.chrome.browser.bookmarkswidget.BookmarkThumbnailWidgetProviderBase;
 import org.chromium.chrome.browser.crash.CrashFileManager;
 import org.chromium.chrome.browser.crash.MinidumpUploadService;
-import org.chromium.chrome.browser.download.DownloadManagerService;
 import org.chromium.chrome.browser.media.MediaCaptureNotificationService;
 import org.chromium.chrome.browser.partnerbookmarks.PartnerBookmarksShim;
 import org.chromium.chrome.browser.physicalweb.PhysicalWeb;
@@ -107,9 +106,6 @@
         // Starts syncing with GSA.
         application.createGsaHelper().startSync();
 
-        DownloadManagerService.getDownloadManagerService(application)
-                .clearPendingDownloadNotifications();
-
         application.initializeSharedClasses();
 
         ShareHelper.clearSharedImages(application);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadBroadcastReceiver.java b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadBroadcastReceiver.java
new file mode 100644
index 0000000..65d4f3c1
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadBroadcastReceiver.java
@@ -0,0 +1,83 @@
+// 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.
+
+package org.chromium.chrome.browser.download;
+
+import android.app.DownloadManager;
+import android.content.ActivityNotFoundException;
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.net.Uri;
+
+/**
+ * This {@link BroadcastReceiver} handles clicks to download notifications and their action buttons.
+ * Clicking on an in-progress or failed download will open the download manager. Clicking on
+ * a complete, successful download will open the file. Clicking on the resume button of a paused
+ * download will relaunch the browser process and try to resume the download from where it is
+ * stopped.
+ */
+public class DownloadBroadcastReceiver extends BroadcastReceiver {
+    @Override
+    public void onReceive(final Context context, Intent intent) {
+        String action = intent.getAction();
+        switch (action) {
+            case DownloadManager.ACTION_NOTIFICATION_CLICKED:
+                openDownload(context, intent);
+                break;
+            case DownloadNotificationService.ACTION_DOWNLOAD_RESUME:
+                resumeDownload(context, intent);
+                break;
+            default:
+                break;
+        }
+    }
+
+    /**
+     * Called to open a given download item that is downloaded by the android DownloadManager.
+     * @param context Context of the receiver.
+     * @param intent Intent from the android DownloadManager.
+     */
+    private void openDownload(final Context context, Intent intent) {
+        long ids[] =
+                intent.getLongArrayExtra(DownloadManager.EXTRA_NOTIFICATION_CLICK_DOWNLOAD_IDS);
+        if (ids == null || ids.length == 0) {
+            DownloadManagerService.openDownloadsPage(context);
+            return;
+        }
+        long id = ids[0];
+        DownloadManager manager =
+                (DownloadManager) context.getSystemService(Context.DOWNLOAD_SERVICE);
+        Uri uri = manager.getUriForDownloadedFile(id);
+        if (uri == null) {
+            // Open the downloads page
+            DownloadManagerService.openDownloadsPage(context);
+        } else {
+            Intent launchIntent = new Intent(Intent.ACTION_VIEW);
+            launchIntent.setDataAndType(uri, manager.getMimeTypeForDownloadedFile(id));
+            launchIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+            try {
+                context.startActivity(launchIntent);
+            } catch (ActivityNotFoundException e) {
+                DownloadManagerService.openDownloadsPage(context);
+            }
+        }
+    }
+
+    /**
+     * Called to handle download resumption. This will call the DownloadNotificationService
+     * to start the browser process asynchronously, and resume the download afterwards.
+     * @param context Context of the receiver.
+     * @param intent Intent from the android DownloadManager.
+     */
+    private void resumeDownload(final Context context, Intent intent) {
+        if (DownloadNotificationService.isDownloadResumptionIntent(intent)) {
+            Intent launchIntent = new Intent(intent);
+            launchIntent.setComponent(new ComponentName(
+                    context.getPackageName(), DownloadNotificationService.class.getName()));
+            context.startService(launchIntent);
+        }
+    }
+}
\ No newline at end of file
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 60fd6c0a..d6c3505d7 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
@@ -24,6 +24,7 @@
 import org.chromium.base.Log;
 import org.chromium.base.ThreadUtils;
 import org.chromium.base.VisibleForTesting;
+import org.chromium.base.annotations.CalledByNative;
 import org.chromium.base.annotations.SuppressFBWarnings;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.IntentHandler;
@@ -91,6 +92,7 @@
             new LongSparseArray<DownloadInfo>();
     private OMADownloadHandler mOMADownloadHandler;
     private DownloadSnackbarController mDownloadSnackbarController;
+    private long mNativeDownloadManagerService;
 
     /**
      * Enum representing status of a download.
@@ -156,6 +158,50 @@
     }
 
     /**
+     * Class representing a pending notification entry.
+     */
+    @VisibleForTesting
+    static class PendingNotification {
+        public final int downloadId;
+        public final String fileName;
+        public final boolean isResumable;
+
+        PendingNotification(int downloadId, String fileName, boolean isResumable) {
+            this.downloadId = downloadId;
+            this.fileName = fileName;
+            this.isResumable = isResumable;
+        }
+
+        /**
+         * Parse the pending notification from a String object in SharedPrefs.
+         *
+         * @param notification String containing the notification ID, file name and whether it is
+         *        resumable.
+         * @return a PendingNotification object.
+         */
+        static PendingNotification parseFromString(String notification) {
+            String[] values = notification.split(",", 3);
+            if (values.length == 3) {
+                try {
+                    int id = Integer.parseInt(values[0]);
+                    boolean isResumable = "1".equals(values[1]);
+                    return new PendingNotification(id, values[2], isResumable);
+                } catch (NumberFormatException nfe) {
+                    Log.w(TAG, "Exception while parsing pending download:" + notification);
+                }
+            }
+            return new PendingNotification(-1, "", false);
+        }
+
+        /**
+         * Generate a string for the PendingNotification instance to be inserted into SharedPrefs.
+         */
+        String getNotificationString() {
+            return downloadId + "," + (isResumable ? "1" : "0") + "," + fileName;
+        }
+    }
+
+    /**
      * Creates DownloadManagerService.
      */
     @SuppressFBWarnings("LI_LAZY_INIT") // Findbugs doesn't see this is only UI thread.
@@ -201,6 +247,16 @@
         mIsUIUpdateScheduled = new AtomicBoolean(false);
         mOMADownloadHandler = new OMADownloadHandler(context);
         mDownloadSnackbarController = new DownloadSnackbarController(context);
+        clearPendingDownloadNotifications();
+        // Note that this technically leaks the native object, however, DownloadManagerService
+        // is a singleton that lives forever and there's no clean shutdown of Chrome on Android.
+        init();
+    }
+
+    @VisibleForTesting
+    protected void init() {
+        mNativeDownloadManagerService = nativeInit();
+        DownloadController.setDownloadNotificationService(this);
     }
 
     @Override
@@ -229,15 +285,9 @@
         if (mSharedPrefs.contains(DOWNLOAD_NOTIFICATION_IDS)) {
             mSharedPrefs.edit().remove(DOWNLOAD_NOTIFICATION_IDS).apply();
         }
-        List<Pair<Integer, String>> notifications =
-                parseDownloadNotificationsFromSharedPrefs(mSharedPrefs);
-        for (Pair<Integer, String> notification : notifications) {
-            if (notification.first > 0) {
-                mDownloadNotifier.cancelNotification(notification.first);
-                Log.w(TAG, "Download failed: Cleared download id:" + notification.first);
-            }
+        if (mSharedPrefs.contains(PENDING_DOWNLOAD_NOTIFICATIONS)) {
+            mSharedPrefs.edit().remove(PENDING_DOWNLOAD_NOTIFICATIONS).apply();
         }
-        mSharedPrefs.edit().remove(PENDING_DOWNLOAD_NOTIFICATIONS).apply();
         if (mSharedPrefs.contains(PENDING_OMA_DOWNLOADS)) {
             Set<String> omaDownloads = getStoredDownloadInfo(mSharedPrefs, PENDING_OMA_DOWNLOADS);
             for (String omaDownload : omaDownloads) {
@@ -252,14 +302,14 @@
      * @param sharedPrefs SharedPreferences that contains the download notifications.
      * @return a list of parsed notifications.
      */
-    static List<Pair<Integer, String>> parseDownloadNotificationsFromSharedPrefs(
+    static List<PendingNotification> parseDownloadNotificationsFromSharedPrefs(
             SharedPreferences sharedPrefs) {
-        List<Pair<Integer, String>> result = new ArrayList<Pair<Integer, String>>();
+        List<PendingNotification> result = new ArrayList<PendingNotification>();
         if (sharedPrefs.contains(DownloadManagerService.PENDING_DOWNLOAD_NOTIFICATIONS)) {
             Set<String> pendingDownloads = DownloadManagerService.getStoredDownloadInfo(
                     sharedPrefs, DownloadManagerService.PENDING_DOWNLOAD_NOTIFICATIONS);
             for (String download : pendingDownloads) {
-                result.add(DownloadManagerService.parseNotificationString(download));
+                result.add(PendingNotification.parseFromString(download));
             }
         }
         return result;
@@ -354,36 +404,6 @@
     }
 
     /**
-     * Parse the notification ID from a String object in SharedPrefs.
-     *
-     * @param notification String containing the notification ID and file name.
-     * @return a pair of notification ID and file name.
-     */
-    static Pair<Integer, String> parseNotificationString(String notification) {
-        int index = notification.indexOf(",");
-        if (index <= 0) return Pair.create(-1, "");
-        try {
-            int id = Integer.parseInt(notification.substring(0, index));
-            return Pair.create(id, notification.substring(index + 1));
-        } catch (NumberFormatException nfe) {
-            Log.w(TAG, "Exception while parsing pending download:" + notification);
-            return Pair.create(-1, "");
-        }
-    }
-
-    /**
-     * Generate a string for the download Id and file name pair to be
-     * inserted into SharedPrefs.
-     *
-     * @param downloadId ID of the download.
-     * @param fileName Name of the file to be downloaded.
-     * @return notification string containing the notification ID and file name.
-     */
-    static String getNotificationString(int downloadId, String fileName) {
-        return downloadId + "," + fileName;
-    }
-
-    /**
      * Broadcast that a download was successful.
      * @param downloadInfo info about the download.
      */
@@ -408,8 +428,8 @@
         Set<String> pendingDownloads =
                 getStoredDownloadInfo(mSharedPrefs, PENDING_DOWNLOAD_NOTIFICATIONS);
         for (String download : pendingDownloads) {
-            Pair<Integer, String> notification = parseNotificationString(download);
-            if (notification.first == downloadId) {
+            PendingNotification notification = PendingNotification.parseFromString(download);
+            if (notification.downloadId == downloadId) {
                 pendingDownloads.remove(download);
                 storeDownloadInfo(PENDING_DOWNLOAD_NOTIFICATIONS, pendingDownloads);
                 break;
@@ -418,15 +438,14 @@
     }
 
     /**
-     * Add a pending download to SharedPrefs, the string consists of both the download ID
-     * and file name.
-     * @param downloadId ID to be stored.
-     * @param fileName Name of the file, used for notifications.
+     * Add a pending download to SharedPrefs, the string consists of the download ID, file name and
+     * whether it is resumable.
+     * @param pendingNotification Pending download entry.
      */
-    private void addPendingDownloadToSharedPrefs(int downloadId, String fileName) {
+    private void addPendingDownloadToSharedPrefs(PendingNotification pendingNotification) {
         Set<String> pendingDownloads =
                 getStoredDownloadInfo(mSharedPrefs, PENDING_DOWNLOAD_NOTIFICATIONS);
-        pendingDownloads.add(getNotificationString(downloadId, fileName));
+        pendingDownloads.add(pendingNotification.getNotificationString());
         storeDownloadInfo(PENDING_DOWNLOAD_NOTIFICATIONS, pendingDownloads);
     }
 
@@ -659,7 +678,8 @@
             if (status == DownloadStatus.IN_PROGRESS) {
                 // A new in-progress download, add an entry to shared prefs to make sure
                 // to clear the notification.
-                addPendingDownloadToSharedPrefs(downloadId, downloadInfo.getFileName());
+                addPendingDownloadToSharedPrefs(new PendingNotification(
+                        downloadId, downloadInfo.getFileName(), downloadInfo.isResumable()));
             }
             mDownloadProgressMap.putIfAbsent(downloadId, progress);
         } else {
@@ -1071,4 +1091,30 @@
             Log.e(TAG, "Cannot find Downloads app", e);
         }
     }
+
+    /**
+     * Called to resume a paused download.
+     * @param downloadId Id of the download.
+     */
+    void resumeDownload(int downloadId, String fileName) {
+        nativeResumeDownload(mNativeDownloadManagerService, downloadId, fileName);
+        mDownloadNotifier.notifyDownloadProgress(
+                new DownloadInfo.Builder()
+                        .setDownloadId(downloadId)
+                        .setFileName(fileName)
+                        .setPercentCompleted(
+                                DownloadNotificationService.INVALID_DOWNLOAD_PERCENTAGE)
+                        .build(),
+                0);
+    }
+
+    @CalledByNative
+    void onResumptionFailed(int downloadId, String fileName) {
+        mDownloadNotifier.notifyDownloadFailed(
+                new DownloadInfo.Builder().setDownloadId(downloadId).setFileName(fileName).build());
+    }
+
+    private native long nativeInit();
+    private native void nativeResumeDownload(
+            long nativeDownloadManagerService, int downloadId, String fileName);
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadNotificationService.java b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadNotificationService.java
index 31ed6497..0690a7e 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadNotificationService.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadNotificationService.java
@@ -8,6 +8,7 @@
 import android.app.NotificationManager;
 import android.app.PendingIntent;
 import android.app.Service;
+import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
 import android.content.SharedPreferences;
@@ -15,10 +16,16 @@
 import android.os.IBinder;
 import android.preference.PreferenceManager;
 import android.support.v4.app.NotificationCompat;
-import android.util.Pair;
 
+import org.chromium.base.Log;
 import org.chromium.base.VisibleForTesting;
+import org.chromium.base.library_loader.ProcessInitException;
 import org.chromium.chrome.R;
+import org.chromium.chrome.browser.ChromeApplication;
+import org.chromium.chrome.browser.init.BrowserParts;
+import org.chromium.chrome.browser.init.ChromeBrowserInitializer;
+import org.chromium.chrome.browser.init.EmptyBrowserParts;
+import org.chromium.chrome.browser.util.IntentUtils;
 import org.chromium.ui.base.LocalizationUtils;
 
 import java.text.NumberFormat;
@@ -30,8 +37,13 @@
  * Chrome gets killed.
  */
 public class DownloadNotificationService extends Service {
+    static final String EXTRA_DOWNLOAD_ID = "DownloadId";
+    static final String EXTRA_DOWNLOAD_FILE_NAME = "DownloadFileName";
+    static final String ACTION_DOWNLOAD_RESUME =
+            "org.chromium.chrome.browser.download.DOWNLOAD_RESUME";
+    static final int INVALID_DOWNLOAD_PERCENTAGE = -1;
     private static final String NOTIFICATION_NAMESPACE = "DownloadNotificationService";
-    private static final int INVALID_DOWNLOAD_PERCENTAGE = -1;
+    private static final String TAG = "DownloadNotification";
     private final IBinder mBinder = new LocalBinder();
     private NotificationManager mNotificationManager;
     private Context mContext;
@@ -75,6 +87,29 @@
 
     @Override
     public int onStartCommand(Intent intent, int flags, int startId) {
+        if (isDownloadResumptionIntent(intent)) {
+            final int downloadId = IntentUtils.safeGetIntExtra(
+                    intent, DownloadNotificationService.EXTRA_DOWNLOAD_ID, -1);
+            final String fileName = IntentUtils.safeGetStringExtra(
+                    intent, DownloadNotificationService.EXTRA_DOWNLOAD_FILE_NAME);
+            BrowserParts parts = new EmptyBrowserParts() {
+                @Override
+                public void finishNativeInitialization() {
+                    DownloadManagerService service =
+                            DownloadManagerService.getDownloadManagerService(
+                                    getApplicationContext());
+                    service.resumeDownload(downloadId, fileName);
+                }
+            };
+            try {
+                ChromeBrowserInitializer.getInstance(mContext).handlePreNativeStartup(parts);
+                ChromeBrowserInitializer.getInstance(mContext).handlePostNativeStartup(true, parts);
+            } catch (ProcessInitException e) {
+                Log.e(TAG, "Unable to load native library.", e);
+                ChromeApplication.reportStartupErrorAndExit(e);
+            }
+        }
+
         // This should restart the service after Chrome gets killed. However, this
         // doesn't work on Android 4.4.2.
         return START_STICKY;
@@ -123,12 +158,25 @@
      * Change a download notification to paused state.
      * @param downloadId ID of the download.
      * @param fileName File name of the download.
+     * @param isResumable whether download is resumable.
      */
-    public void notifyDownloadPaused(int downloadId, String fileName) {
+    public void notifyDownloadPaused(int downloadId, String fileName, boolean isResumable) {
         NotificationCompat.Builder builder = buildNotification(
                 android.R.drawable.ic_media_pause,
                 fileName,
                 mContext.getResources().getString(R.string.download_notification_paused));
+        if (isResumable) {
+            ComponentName component = new ComponentName(
+                    mContext.getPackageName(), DownloadBroadcastReceiver.class.getName());
+            Intent intent = new Intent(ACTION_DOWNLOAD_RESUME);
+            intent.setComponent(component);
+            intent.putExtra(EXTRA_DOWNLOAD_ID, downloadId);
+            intent.putExtra(EXTRA_DOWNLOAD_FILE_NAME, fileName);
+            builder.addAction(android.R.drawable.stat_sys_download_done,
+                    mContext.getResources().getString(R.string.download_notification_resume_button),
+                    PendingIntent.getBroadcast(
+                            mContext, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT));
+        }
         updateNotification(downloadId, builder.build());
     }
 
@@ -171,11 +219,12 @@
     void pauseAllDownloads() {
         SharedPreferences sharedPrefs =
                 PreferenceManager.getDefaultSharedPreferences(mContext);
-        List<Pair<Integer, String>> notifications =
+        List<DownloadManagerService.PendingNotification> notifications =
                 DownloadManagerService.parseDownloadNotificationsFromSharedPrefs(sharedPrefs);
-        for (Pair<Integer, String> notification : notifications) {
-            if (notification.first > 0) {
-                notifyDownloadPaused(notification.first, notification.second);
+        for (DownloadManagerService.PendingNotification notification : notifications) {
+            if (notification.downloadId > 0) {
+                notifyDownloadPaused(
+                        notification.downloadId, notification.fileName, notification.isResumable);
             }
         }
     }
@@ -207,4 +256,23 @@
     void updateNotification(int id, Notification notification) {
         mNotificationManager.notify(NOTIFICATION_NAMESPACE, id, notification);
     }
+
+    /**
+     * Checks if an intent is about to resume a download.
+     * @param intent An intent to validate.
+     * @return true if the intent is for download resumption, or false otherwise.
+     */
+    static boolean isDownloadResumptionIntent(Intent intent) {
+        if (!intent.hasExtra(DownloadNotificationService.EXTRA_DOWNLOAD_ID)
+                || !intent.hasExtra(DownloadNotificationService.EXTRA_DOWNLOAD_FILE_NAME)) {
+            return false;
+        }
+        final int downloadId = IntentUtils.safeGetIntExtra(
+                intent, DownloadNotificationService.EXTRA_DOWNLOAD_ID, -1);
+        if (downloadId == -1) return false;
+        final String fileName = IntentUtils.safeGetStringExtra(
+                intent, DownloadNotificationService.EXTRA_DOWNLOAD_FILE_NAME);
+        if (fileName == null) return false;
+        return true;
+    }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/OpenDownloadReceiver.java b/chrome/android/java/src/org/chromium/chrome/browser/download/OpenDownloadReceiver.java
deleted file mode 100644
index b6ee223d..0000000
--- a/chrome/android/java/src/org/chromium/chrome/browser/download/OpenDownloadReceiver.java
+++ /dev/null
@@ -1,52 +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.
-
-package org.chromium.chrome.browser.download;
-
-import android.app.DownloadManager;
-import android.content.ActivityNotFoundException;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.net.Uri;
-
-/**
- * This {@link BroadcastReceiver} handles clicks to notifications that
- * downloads from the browser are in progress/complete.  Clicking on an
- * in-progress or failed download will open the download manager.  Clicking on
- * a complete, successful download will open the file.
- */
-public class OpenDownloadReceiver extends BroadcastReceiver {
-    @Override
-    public void onReceive(final Context context, Intent intent) {
-        String action = intent.getAction();
-        if (!DownloadManager.ACTION_NOTIFICATION_CLICKED.equals(action)) {
-            DownloadManagerService.openDownloadsPage(context);
-            return;
-        }
-        long ids[] = intent.getLongArrayExtra(
-                DownloadManager.EXTRA_NOTIFICATION_CLICK_DOWNLOAD_IDS);
-        if (ids == null || ids.length == 0) {
-            DownloadManagerService.openDownloadsPage(context);
-            return;
-        }
-        long id = ids[0];
-        DownloadManager manager = (DownloadManager) context.getSystemService(
-                Context.DOWNLOAD_SERVICE);
-        Uri uri = manager.getUriForDownloadedFile(id);
-        if (uri == null) {
-            // Open the downloads page
-            DownloadManagerService.openDownloadsPage(context);
-        } else {
-            Intent launchIntent = new Intent(Intent.ACTION_VIEW);
-            launchIntent.setDataAndType(uri, manager.getMimeTypeForDownloadedFile(id));
-            launchIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-            try {
-                context.startActivity(launchIntent);
-            } catch (ActivityNotFoundException e) {
-                DownloadManagerService.openDownloadsPage(context);
-            }
-        }
-    }
-}
\ No newline at end of file
diff --git a/chrome/android/java/strings/android_chrome_strings.grd b/chrome/android/java/strings/android_chrome_strings.grd
index 8b9b17c3..cbaaf07f 100644
--- a/chrome/android/java/strings/android_chrome_strings.grd
+++ b/chrome/android/java/strings/android_chrome_strings.grd
@@ -1453,6 +1453,9 @@
       <message name="IDS_DOWNLOAD_NOTIFICATION_PAUSED" desc="Download notification to be displayed when a download pauses.">
         Download paused.
       </message>
+      <message name="IDS_DOWNLOAD_NOTIFICATION_RESUME_BUTTON" desc="Text on the button that resumes a paused download.">
+        Resume
+      </message>
       <message name="IDS_DOWNLOAD_FAILED_REASON_FILE_ALREADY_EXISTS" desc="Message to explain that the download failed because file already exists.">
         <ph name="FILE_NAME">%1$s<ex>http://abc.com/test.pdf</ex></ph> download prevented because file already exists.
       </message>
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/TabsOpenedFromExternalAppTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/TabsOpenedFromExternalAppTest.java
index 440624e..1b9d64f 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/TabsOpenedFromExternalAppTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/TabsOpenedFromExternalAppTest.java
@@ -372,12 +372,8 @@
      * when the user has navigated elsewhere manually in the same tab.
      * @throws InterruptedException
      */
-    /**
-     * @LargeTest
-     * @Feature({"Navigation"})
-     * Bug 6467101
-     */
-    @FlakyTest
+    @LargeTest
+    @Feature({"Navigation"})
     public void testNewTabAfterNavigation() throws InterruptedException {
         startMainActivityFromLauncher();
 
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadManagerServiceTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadManagerServiceTest.java
index d482a981..efa4f28 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadManagerServiceTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadManagerServiceTest.java
@@ -255,6 +255,9 @@
         protected long addCompletedDownload(DownloadInfo downloadInfo) {
             return 1L;
         }
+
+        @Override
+        protected void init() {}
     }
 
     private static Handler getTestHandler() {
@@ -419,15 +422,11 @@
         assertTrue("All downloads should be updated.", matchSet.mMatches.isEmpty());
 
         // Check if notifications are removed when clearPendingNotifications is called.
-        matchSet = new OneTimeMatchSet(download1.getDownloadId(),
-                download2.getDownloadId(), download3.getDownloadId());
-        notifier.expect(MethodID.CANCEL_DOWNLOAD_ID, matchSet)
-                .andThen(MethodID.CANCEL_DOWNLOAD_ID, matchSet)
-                .andThen(MethodID.CANCEL_DOWNLOAD_ID, matchSet);
-
         dService.clearPendingDownloadNotifications();
-        notifier.waitTillExpectedCallsComplete();
-        assertTrue("All downloads should be removed.", matchSet.mMatches.isEmpty());
+        Set<String> downloads = dService.getStoredDownloadInfo(
+                PreferenceManager.getDefaultSharedPreferences(getTestContext()),
+                DownloadManagerService.PENDING_DOWNLOAD_NOTIFICATIONS);
+        assertTrue("All downloads should be removed.", downloads.isEmpty());
     }
 
     /**
@@ -567,4 +566,21 @@
                         .build()));
     }
 
+    @SmallTest
+    @Feature({"Download"})
+    public void testParseDownloadNotifications() {
+        String notification = "1,0,test.pdf";
+        DownloadManagerService.PendingNotification pendingNotification =
+                DownloadManagerService.PendingNotification.parseFromString(notification);
+        assertEquals(1, pendingNotification.downloadId);
+        assertEquals("test.pdf", pendingNotification.fileName);
+        assertFalse(pendingNotification.isResumable);
+
+        notification = "2,1,test,2.pdf";
+        pendingNotification =
+                DownloadManagerService.PendingNotification.parseFromString(notification);
+        assertEquals(2, pendingNotification.downloadId);
+        assertEquals("test,2.pdf", pendingNotification.fileName);
+        assertTrue(pendingNotification.isResumable);
+    }
 }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadNotificationServiceTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadNotificationServiceTest.java
index a92991c..51507d7 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadNotificationServiceTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadNotificationServiceTest.java
@@ -73,8 +73,10 @@
         Context mockContext = new AdvancedMockContext(getSystemContext());
         getService().setContext(mockContext);
         Set<String> notifications = new HashSet<String>();
-        notifications.add(DownloadManagerService.getNotificationString(1, "test1"));
-        notifications.add(DownloadManagerService.getNotificationString(2, "test2"));
+        notifications.add(new DownloadManagerService.PendingNotification(
+                1, "test1", true).getNotificationString());
+        notifications.add(new DownloadManagerService.PendingNotification(
+                2, "test2", true).getNotificationString());
         SharedPreferences sharedPrefs =
                 PreferenceManager.getDefaultSharedPreferences(mockContext);
         SharedPreferences.Editor editor = sharedPrefs.edit();
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index 5a89dab..87bcd4c2 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -858,7 +858,6 @@
       "//third_party/isimpledom",
       "//third_party/wtl",
       "//ui/metro_viewer",
-      "//win8:metro_viewer",
     ]
 
     all_dependent_configs = [ ":browser_win_linker_flags" ]
diff --git a/chrome/browser/android/chrome_jni_registrar.cc b/chrome/browser/android/chrome_jni_registrar.cc
index a0f30cc..ec04fc9b 100644
--- a/chrome/browser/android/chrome_jni_registrar.cc
+++ b/chrome/browser/android/chrome_jni_registrar.cc
@@ -39,6 +39,7 @@
 #include "chrome/browser/android/document/document_web_contents_delegate.h"
 #include "chrome/browser/android/dom_distiller/distiller_ui_handle_android.h"
 #include "chrome/browser/android/download/chrome_download_delegate.h"
+#include "chrome/browser/android/download/download_manager_service.h"
 #include "chrome/browser/android/favicon_helper.h"
 #include "chrome/browser/android/feature_utilities.h"
 #include "chrome/browser/android/feedback/connectivity_checker.h"
@@ -255,6 +256,8 @@
     {"DomDistillerServiceFactory",
      dom_distiller::android::DomDistillerServiceFactoryAndroid::Register},
     {"DomDistillerTabUtils", RegisterDomDistillerTabUtils},
+    {"DownloadManagerService",
+     DownloadManagerService::RegisterDownloadManagerService},
     {"DownloadOverwriteInfoBarDelegate",
      RegisterDownloadOverwriteInfoBarDelegate},
     {"EditBookmarkHelper", RegisterEditBookmarkHelper},
diff --git a/chrome/browser/android/download/download_manager_service.cc b/chrome/browser/android/download/download_manager_service.cc
new file mode 100644
index 0000000..3d4fe8a
--- /dev/null
+++ b/chrome/browser/android/download/download_manager_service.cc
@@ -0,0 +1,121 @@
+// 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.
+
+#include "chrome/browser/android/download/download_manager_service.h"
+
+#include "base/android/jni_string.h"
+#include "base/message_loop/message_loop.h"
+#include "base/time/time.h"
+#include "chrome/browser/profiles/profile_manager.h"
+#include "content/public/browser/android/download_controller_android.h"
+#include "content/public/browser/browser_context.h"
+#include "content/public/browser/download_item.h"
+#include "jni/DownloadManagerService_jni.h"
+
+using base::android::JavaParamRef;
+using base::android::ConvertJavaStringToUTF8;
+using base::android::ConvertUTF8ToJavaString;
+
+namespace {
+// The retry interval when resuming a download. This is needed because
+// when the browser process is launched, we have to wait until the download
+// history get loaded before a download can be resumed. However, we don't want
+// to retry after a long period of time as the same download Id can be reused
+// later.
+const int kResumeRetryIntervalInMilliseconds = 3000;
+}
+
+// static
+bool DownloadManagerService::RegisterDownloadManagerService(JNIEnv* env) {
+  return RegisterNativesImpl(env);
+}
+
+static jlong Init(JNIEnv* env, const JavaParamRef<jobject>& jobj) {
+  Profile* profile = ProfileManager::GetActiveUserProfile();
+  content::DownloadManager* manager =
+      content::BrowserContext::GetDownloadManager(profile);
+  DownloadManagerService* service =
+      new DownloadManagerService(env, jobj, manager);
+  return reinterpret_cast<intptr_t>(service);
+}
+
+DownloadManagerService::DownloadManagerService(
+    JNIEnv* env,
+    jobject obj,
+    content::DownloadManager* manager)
+    : java_ref_(env, obj), manager_(manager) {
+  manager_->AddObserver(this);
+}
+
+DownloadManagerService::~DownloadManagerService() {
+  if (manager_)
+    manager_->RemoveObserver(this);
+}
+
+void DownloadManagerService::ResumeDownload(JNIEnv* env,
+                                            jobject obj,
+                                            uint32_t download_id,
+                                            jstring fileName) {
+  ResumeDownloadInternal(download_id, ConvertJavaStringToUTF8(env, fileName),
+                         true);
+}
+
+void DownloadManagerService::ManagerGoingDown(
+    content::DownloadManager* manager) {
+  manager_ = nullptr;
+}
+
+void DownloadManagerService::ResumeDownloadItem(content::DownloadItem* item,
+                                                const std::string& fileName) {
+  if (!item->CanResume()) {
+    OnResumptionFailed(item->GetId(), fileName);
+    return;
+  }
+  item->AddObserver(content::DownloadControllerAndroid::Get());
+  item->Resume();
+  if (!resume_callback_for_testing_.is_null())
+    resume_callback_for_testing_.Run(true);
+}
+
+void DownloadManagerService::ResumeDownloadInternal(uint32_t download_id,
+                                                    const std::string& fileName,
+                                                    bool retry) {
+  if (!manager_) {
+    OnResumptionFailed(download_id, fileName);
+    return;
+  }
+  content::DownloadItem* item = manager_->GetDownload(download_id);
+  if (item) {
+    ResumeDownloadItem(item, fileName);
+    return;
+  }
+  if (!retry) {
+    OnResumptionFailed(download_id, fileName);
+    return;
+  }
+  // Post a delayed task to wait for the download history to load the download
+  // item. If the download item is not loaded when the delayed task runs, show
+  // an download failed notification. Alternatively, we can have the
+  // DownloadManager inform us when a download item is created. However, there
+  // is no guarantee when the download item will be created, since the newly
+  // created item might not be loaded from download history. So user might wait
+  // indefinitely to see the failed notification. See http://crbug.com/577893.
+  base::MessageLoop::current()->PostDelayedTask(
+      FROM_HERE,
+      base::Bind(&DownloadManagerService::ResumeDownloadInternal,
+                 base::Unretained(this), download_id, fileName, false),
+      base::TimeDelta::FromMilliseconds(kResumeRetryIntervalInMilliseconds));
+}
+
+void DownloadManagerService::OnResumptionFailed(uint32_t download_id,
+                                                const std::string& fileName) {
+  if (!java_ref_.is_null()) {
+    JNIEnv* env = base::android::AttachCurrentThread();
+    Java_DownloadManagerService_onResumptionFailed(
+        env, java_ref_.obj(), download_id,
+        ConvertUTF8ToJavaString(env, fileName).obj());
+  }
+  if (!resume_callback_for_testing_.is_null())
+    resume_callback_for_testing_.Run(false);
+}
diff --git a/chrome/browser/android/download/download_manager_service.h b/chrome/browser/android/download/download_manager_service.h
new file mode 100644
index 0000000..6d5a935a
--- /dev/null
+++ b/chrome/browser/android/download/download_manager_service.h
@@ -0,0 +1,76 @@
+// 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 CHROME_BROWSER_ANDROID_DOWNLOAD_DOWNLOAD_MANAGER_SERVICE_H_
+#define CHROME_BROWSER_ANDROID_DOWNLOAD_DOWNLOAD_MANAGER_SERVICE_H_
+
+#include <jni.h>
+#include <string>
+
+#include "base/android/scoped_java_ref.h"
+#include "base/callback.h"
+#include "base/macros.h"
+#include "content/public/browser/download_manager.h"
+
+namespace content {
+class DownloadItem;
+}
+
+// Native side of DownloadManagerService.java. The native object is owned by its
+// Java object.
+class DownloadManagerService : public content::DownloadManager::Observer {
+ public:
+  // JNI registration.
+  static bool RegisterDownloadManagerService(JNIEnv* env);
+
+  DownloadManagerService(JNIEnv* env,
+                         jobject jobj,
+                         content::DownloadManager* manager);
+  ~DownloadManagerService() override;
+
+  // Called to resume downloading the item that has ID equal to |download_id|.
+  // If the DownloadItem is not yet created, put the ID into
+  // |pending_download_ids_|.
+  void ResumeDownload(JNIEnv* env,
+                      jobject obj,
+                      uint32_t download_id,
+                      jstring fileName);
+
+  // content::DownloadManager::Observer methods.
+  void ManagerGoingDown(content::DownloadManager* manager) override;
+
+ private:
+  // For testing.
+  friend class DownloadManagerServiceTest;
+
+  // Resume downloading the given DownloadItem.
+  void ResumeDownloadItem(content::DownloadItem* item,
+                          const std::string& fileName);
+
+  // Helper function to start the download resumption. If |retry| is true,
+  // chrome will retry the resumption if the download item is not loaded.
+  void ResumeDownloadInternal(uint32_t download_id,
+                              const std::string& fileName,
+                              bool retry);
+
+  // Called to notify the java side that download resumption failed.
+  void OnResumptionFailed(uint32_t download_id, const std::string& fileName);
+
+  typedef base::Callback<void(bool)> ResumeCallback;
+  void set_resume_callback_for_testing(const ResumeCallback& resume_cb) {
+    resume_callback_for_testing_ = resume_cb;
+  }
+
+  // Reference to the Java object.
+  base::android::ScopedJavaGlobalRef<jobject> java_ref_;
+
+  // Download manager this class observes
+  content::DownloadManager* manager_;
+
+  ResumeCallback resume_callback_for_testing_;
+
+  DISALLOW_COPY_AND_ASSIGN(DownloadManagerService);
+};
+
+#endif  // CHROME_BROWSER_ANDROID_DOWNLOAD_DOWNLOAD_MANAGER_SERVICE_H_
diff --git a/chrome/browser/android/download/download_manager_service_unittest.cc b/chrome/browser/android/download/download_manager_service_unittest.cc
new file mode 100644
index 0000000..c400c8a
--- /dev/null
+++ b/chrome/browser/android/download/download_manager_service_unittest.cc
@@ -0,0 +1,222 @@
+// 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.
+
+#include "chrome/browser/android/download/download_manager_service.h"
+
+#include "base/android/jni_android.h"
+#include "base/android/jni_string.h"
+#include "base/bind.h"
+#include "base/macros.h"
+#include "base/message_loop/message_loop.h"
+#include "content/public/browser/download_item.h"
+#include "content/public/browser/download_manager.h"
+#include "content/public/browser/download_url_parameters.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "url/origin.h"
+
+using ::testing::_;
+
+namespace content {
+class BrowserContext;
+class ByteStreamReader;
+class DownloadManagerDelegate;
+struct DownloadCreateInfo;
+}
+
+// Mock implementation of content::DownloadItem.
+class MockDownloadItem : public content::DownloadItem {
+ public:
+  explicit MockDownloadItem(bool can_resume) : can_resume_(can_resume) {}
+  ~MockDownloadItem() override {}
+  bool CanResume() const override { return can_resume_; }
+
+  MOCK_METHOD1(AddObserver, void(content::DownloadItem::Observer*));
+  MOCK_METHOD1(RemoveObserver, void(content::DownloadItem::Observer*));
+  MOCK_METHOD0(UpdateObservers, void());
+  MOCK_METHOD0(ValidateDangerousDownload, void());
+  MOCK_METHOD1(StealDangerousDownload,
+               void(const content::DownloadItem::AcquireFileCallback&));
+  MOCK_METHOD0(Pause, void());
+  MOCK_METHOD0(Resume, void());
+  MOCK_METHOD1(Cancel, void(bool));
+  MOCK_METHOD0(Remove, void());
+  MOCK_METHOD0(OpenDownload, void());
+  MOCK_METHOD0(ShowDownloadInShell, void());
+  MOCK_CONST_METHOD0(GetId, uint32_t());
+  MOCK_CONST_METHOD0(GetState, content::DownloadItem::DownloadState());
+  MOCK_CONST_METHOD0(GetLastReason, content::DownloadInterruptReason());
+  MOCK_CONST_METHOD0(IsPaused, bool());
+  MOCK_CONST_METHOD0(IsTemporary, bool());
+  MOCK_CONST_METHOD0(IsDone, bool());
+  MOCK_CONST_METHOD0(GetURL, const GURL&());
+  MOCK_CONST_METHOD0(GetUrlChain, std::vector<GURL>&());
+  MOCK_CONST_METHOD0(GetOriginalUrl, const GURL&());
+  MOCK_CONST_METHOD0(GetReferrerUrl, const GURL&());
+  MOCK_CONST_METHOD0(GetTabUrl, const GURL&());
+  MOCK_CONST_METHOD0(GetTabReferrerUrl, const GURL&());
+  MOCK_CONST_METHOD0(GetSuggestedFilename, std::string());
+  MOCK_CONST_METHOD0(GetContentDisposition, std::string());
+  MOCK_CONST_METHOD0(GetMimeType, std::string());
+  MOCK_CONST_METHOD0(GetOriginalMimeType, std::string());
+  MOCK_CONST_METHOD0(GetRemoteAddress, std::string());
+  MOCK_CONST_METHOD0(HasUserGesture, bool());
+  MOCK_CONST_METHOD0(GetTransitionType, ui::PageTransition());
+  MOCK_CONST_METHOD0(GetLastModifiedTime, const std::string&());
+  MOCK_CONST_METHOD0(GetETag, const std::string&());
+  MOCK_CONST_METHOD0(IsSavePackageDownload, bool());
+  MOCK_CONST_METHOD0(GetFullPath, const base::FilePath&());
+  MOCK_CONST_METHOD0(GetTargetFilePath, const base::FilePath&());
+  MOCK_CONST_METHOD0(GetForcedFilePath, const base::FilePath&());
+  MOCK_CONST_METHOD0(GetFileNameToReportUser, base::FilePath());
+  MOCK_CONST_METHOD0(GetTargetDisposition,
+                     content::DownloadItem::TargetDisposition());
+  MOCK_CONST_METHOD0(GetHash, const std::string&());
+  MOCK_CONST_METHOD0(GetHashState, const std::string&());
+  MOCK_CONST_METHOD0(GetFileExternallyRemoved, bool());
+  MOCK_METHOD1(DeleteFile, void(const base::Callback<void(bool)>&));
+  MOCK_CONST_METHOD0(IsDangerous, bool());
+  MOCK_CONST_METHOD0(GetDangerType, content::DownloadDangerType());
+  MOCK_CONST_METHOD1(TimeRemaining, bool(base::TimeDelta*));
+  MOCK_CONST_METHOD0(CurrentSpeed, int64_t());
+  MOCK_CONST_METHOD0(PercentComplete, int());
+  MOCK_CONST_METHOD0(AllDataSaved, bool());
+  MOCK_CONST_METHOD0(GetTotalBytes, int64_t());
+  MOCK_CONST_METHOD0(GetReceivedBytes, int64_t());
+  MOCK_CONST_METHOD0(GetStartTime, base::Time());
+  MOCK_CONST_METHOD0(GetEndTime, base::Time());
+  MOCK_METHOD0(CanShowInFolder, bool());
+  MOCK_METHOD0(CanOpenDownload, bool());
+  MOCK_METHOD0(ShouldOpenFileBasedOnExtension, bool());
+  MOCK_CONST_METHOD0(GetOpenWhenComplete, bool());
+  MOCK_METHOD0(GetAutoOpened, bool());
+  MOCK_CONST_METHOD0(GetOpened, bool());
+  MOCK_CONST_METHOD0(GetBrowserContext, content::BrowserContext*());
+  MOCK_CONST_METHOD0(GetWebContents, content::WebContents*());
+  MOCK_METHOD1(OnContentCheckCompleted, void(content::DownloadDangerType));
+  MOCK_METHOD1(SetOpenWhenComplete, void(bool));
+  MOCK_METHOD1(SetIsTemporary, void(bool));
+  MOCK_METHOD1(SetOpened, void(bool));
+  MOCK_METHOD1(SetDisplayName, void(const base::FilePath&));
+  MOCK_CONST_METHOD1(DebugString, std::string(bool));
+
+ private:
+  bool can_resume_;
+};
+
+// Mock implementation of content::DownloadManager.
+class MockDownloadManager : public content::DownloadManager {
+ public:
+  MockDownloadManager() {}
+  ~MockDownloadManager() override {}
+
+  MOCK_METHOD1(SetDelegate, void(content::DownloadManagerDelegate*));
+  MOCK_CONST_METHOD0(GetDelegate, content::DownloadManagerDelegate*());
+  MOCK_METHOD0(Shutdown, void());
+  MOCK_METHOD1(GetAllDownloads, void(DownloadVector*));
+  MOCK_METHOD3(RemoveDownloadsByOriginAndTime,
+               int(const url::Origin&, base::Time, base::Time));
+  MOCK_METHOD2(RemoveDownloadsBetween, int(base::Time, base::Time));
+  MOCK_METHOD1(RemoveDownloads, int(base::Time));
+  MOCK_METHOD0(RemoveAllDownloads, int());
+  void DownloadUrl(scoped_ptr<content::DownloadUrlParameters>) override {}
+  MOCK_METHOD1(AddObserver, void(content::DownloadManager::Observer*));
+  MOCK_METHOD1(RemoveObserver, void(content::DownloadManager::Observer*));
+  MOCK_CONST_METHOD0(InProgressCount, int());
+  MOCK_CONST_METHOD0(NonMaliciousInProgressCount, int());
+  MOCK_CONST_METHOD0(GetBrowserContext, content::BrowserContext*());
+  MOCK_METHOD0(CheckForHistoryFilesRemoval, void());
+  void StartDownload(
+      scoped_ptr<content::DownloadCreateInfo>,
+      scoped_ptr<content::ByteStreamReader>,
+      const content::DownloadUrlParameters::OnStartedCallback&) override {}
+  content::DownloadItem* CreateDownloadItem(
+      uint32_t id,
+      const base::FilePath& current_path,
+      const base::FilePath& target_path,
+      const std::vector<GURL>& url_chain,
+      const GURL& referrer_url,
+      const std::string& mime_type,
+      const std::string& original_mime_type,
+      const base::Time& start_time,
+      const base::Time& end_time,
+      const std::string& etag,
+      const std::string& last_modified,
+      int64_t received_bytes,
+      int64_t total_bytes,
+      content::DownloadItem::DownloadState state,
+      content::DownloadDangerType danger_type,
+      content::DownloadInterruptReason interrupt_reason,
+      bool opened) override {
+    return nullptr;
+  }
+  content::DownloadItem* GetDownload(uint32_t id) override {
+    return download_item_.get();
+  }
+  void SetDownload(MockDownloadItem* item) { download_item_.reset(item); }
+
+ private:
+  scoped_ptr<MockDownloadItem> download_item_;
+};
+
+class DownloadManagerServiceTest : public testing::Test {
+ public:
+  DownloadManagerServiceTest()
+      : service_(
+            new DownloadManagerService(base::android::AttachCurrentThread(),
+                                       nullptr,
+                                       &manager_)),
+        finished_(false),
+        success_(false) {}
+
+  void OnResumptionDone(bool success) {
+    finished_ = true;
+    success_ = success;
+  }
+
+  void StartDownload(int download_id) {
+    JNIEnv* env = base::android::AttachCurrentThread();
+    service_->set_resume_callback_for_testing(base::Bind(
+        &DownloadManagerServiceTest::OnResumptionDone, base::Unretained(this)));
+    service_->ResumeDownload(
+        env, nullptr, download_id,
+        base::android::ConvertUTF8ToJavaString(env, "test").obj());
+    while (!finished_)
+      message_loop_.RunUntilIdle();
+  }
+
+  void CreateDownloadItem(bool can_resume) {
+    manager_.SetDownload(new MockDownloadItem(can_resume));
+  }
+
+ protected:
+  base::MessageLoop message_loop_;
+  MockDownloadManager manager_;
+  DownloadManagerService* service_;
+  bool finished_;
+  bool success_;
+
+  DISALLOW_COPY_AND_ASSIGN(DownloadManagerServiceTest);
+};
+
+// Test that resumption will fail if no download item is found before times out.
+TEST_F(DownloadManagerServiceTest, ResumptionTimeOut) {
+  StartDownload(1);
+  EXPECT_FALSE(success_);
+}
+
+// Test that resumption succeeds if the download item is found and can be
+// resumed.
+TEST_F(DownloadManagerServiceTest, ResumptionWithResumableItem) {
+  CreateDownloadItem(true);
+  StartDownload(1);
+  EXPECT_TRUE(success_);
+}
+
+// Test that resumption fails if the target download item is not resumable.
+TEST_F(DownloadManagerServiceTest, ResumptionWithNonResumableItem) {
+  CreateDownloadItem(false);
+  StartDownload(1);
+  EXPECT_FALSE(success_);
+}
diff --git a/chrome/browser/browser_process_platform_part.h b/chrome/browser/browser_process_platform_part.h
index d39671b1..08d1eda5 100644
--- a/chrome/browser/browser_process_platform_part.h
+++ b/chrome/browser/browser_process_platform_part.h
@@ -14,8 +14,6 @@
 #include "chrome/browser/browser_process_platform_part_chromeos.h"
 #elif defined(OS_MACOSX) && !defined(OS_IOS)
 #include "chrome/browser/browser_process_platform_part_mac.h"
-#elif defined(OS_WIN)
-#include "chrome/browser/browser_process_platform_part_aurawin.h"
 #else
 #include "chrome/browser/browser_process_platform_part_base.h"
 typedef BrowserProcessPlatformPartBase BrowserProcessPlatformPart;
diff --git a/chrome/browser/browser_process_platform_part_aurawin.cc b/chrome/browser/browser_process_platform_part_aurawin.cc
deleted file mode 100644
index dd6635bf..0000000
--- a/chrome/browser/browser_process_platform_part_aurawin.cc
+++ /dev/null
@@ -1,72 +0,0 @@
-// Copyright (c) 2013 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/browser_process_platform_part_aurawin.h"
-
-#include "base/command_line.h"
-#include "base/logging.h"
-#include "base/prefs/pref_service.h"
-#include "base/process/kill.h"
-#include "base/win/windows_version.h"
-#include "chrome/browser/browser_process.h"
-#include "chrome/browser/chrome_notification_types.h"
-#include "chrome/browser/first_run/upgrade_util.h"
-#include "chrome/browser/first_run/upgrade_util_win.h"
-#include "chrome/browser/lifetime/application_lifetime.h"
-#include "chrome/browser/metro_viewer/chrome_metro_viewer_process_host_aurawin.h"
-#include "chrome/common/chrome_switches.h"
-#include "chrome/common/pref_names.h"
-#include "content/public/browser/notification_service.h"
-
-#include "ui/aura/remote_window_tree_host_win.h"
-#include "ui/base/ui_base_switches.h"
-
-BrowserProcessPlatformPart::BrowserProcessPlatformPart() {
-  if (base::win::GetVersion() >= base::win::VERSION_WIN7) {
-    // Tell metro viewer to close when we are shutting down.
-    registrar_.Add(this, chrome::NOTIFICATION_APP_TERMINATING,
-                   content::NotificationService::AllSources());
-  }
-}
-
-BrowserProcessPlatformPart::~BrowserProcessPlatformPart() {
-}
-
-void BrowserProcessPlatformPart::OnMetroViewerProcessTerminated() {
-  metro_viewer_process_host_.reset(NULL);
-}
-
-void BrowserProcessPlatformPart::PlatformSpecificCommandLineProcessing(
-    const base::CommandLine& command_line) {
-  // Check for Windows 8 specific commandlines requesting that this process
-  // either connect to an existing viewer or launch a new viewer and
-  // synchronously wait for it to connect.
-
-  bool launch = command_line.HasSwitch(switches::kViewerLaunchViaAppId);
-  bool connect = (launch ||
-                  (command_line.HasSwitch(switches::kViewerConnect) &&
-                   !metro_viewer_process_host_.get()));
-  if (!connect)
-    return;
-  // Create a host to connect to the Metro viewer process over IPC.
-  metro_viewer_process_host_.reset(new ChromeMetroViewerProcessHost());
-  if (launch) {
-    CHECK(metro_viewer_process_host_->LaunchViewerAndWaitForConnection(
-        command_line.GetSwitchValueNative(
-            switches::kViewerLaunchViaAppId)));
-  }
-}
-
-void BrowserProcessPlatformPart::Observe(
-    int type,
-    const content::NotificationSource& source,
-    const content::NotificationDetails& details) {
-
-  DCHECK(type == chrome::NOTIFICATION_APP_TERMINATING);
-  PrefService* pref_service = g_browser_process->local_state();
-  bool is_relaunch = pref_service->GetBoolean(prefs::kWasRestarted);
-  if (is_relaunch) {
-    // TODO(scottmg): A lot of this can be removed http://crbug.com/558054.
-  }
-}
diff --git a/chrome/browser/browser_process_platform_part_aurawin.h b/chrome/browser/browser_process_platform_part_aurawin.h
deleted file mode 100644
index 06dec47..0000000
--- a/chrome/browser/browser_process_platform_part_aurawin.h
+++ /dev/null
@@ -1,45 +0,0 @@
-// Copyright (c) 2013 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_BROWSER_PROCESS_PLATFORM_PART_AURAWIN_H_
-#define CHROME_BROWSER_BROWSER_PROCESS_PLATFORM_PART_AURAWIN_H_
-
-#include "base/compiler_specific.h"
-#include "base/macros.h"
-#include "base/memory/scoped_ptr.h"
-#include "chrome/browser/browser_process_platform_part_base.h"
-#include "content/public/browser/notification_observer.h"
-#include "content/public/browser/notification_registrar.h"
-
-class ChromeMetroViewerProcessHost;
-
-class BrowserProcessPlatformPart : public BrowserProcessPlatformPartBase,
-                                   public content::NotificationObserver {
- public:
-  BrowserProcessPlatformPart();
-  ~BrowserProcessPlatformPart() override;
-
-  // Invoked when the ASH metro viewer process on Windows 8 exits.
-  void OnMetroViewerProcessTerminated();
-
-  // Overridden from BrowserProcessPlatformPartBase:
-  void PlatformSpecificCommandLineProcessing(
-      const base::CommandLine& command_line) override;
-
-  // content::NotificationObserver method:
-  void Observe(int type,
-               const content::NotificationSource& source,
-               const content::NotificationDetails& details) override;
-
- private:
-  // Hosts the channel for the Windows 8 metro viewer process which runs in
-  // the ASH environment.
-  scoped_ptr<ChromeMetroViewerProcessHost> metro_viewer_process_host_;
-
-  content::NotificationRegistrar registrar_;
-
-  DISALLOW_COPY_AND_ASSIGN(BrowserProcessPlatformPart);
-};
-
-#endif  // CHROME_BROWSER_BROWSER_PROCESS_PLATFORM_PART_AURAWIN_H_
diff --git a/chrome/browser/chromeos/extensions/device_local_account_management_policy_provider.cc b/chrome/browser/chromeos/extensions/device_local_account_management_policy_provider.cc
index e77c8da..3bb43cd 100644
--- a/chrome/browser/chromeos/extensions/device_local_account_management_policy_provider.cc
+++ b/chrome/browser/chromeos/extensions/device_local_account_management_policy_provider.cc
@@ -248,16 +248,16 @@
     emk::kWebview,
 };
 
-// List of permissions based on [1] and [2].  Since Public Session users may be
-// fully unaware of any apps being installed, their consent to access any kind
-// of sensitive information cannot be assumed.  Therefore only APIs are
-// whitelisted which should not leak sensitive data to the caller.  Since the
-// privacy boundary is drawn at the API level, no safeguards are required to
-// prevent exfiltration and thus apps may communicate freely over any kind of
-// network.
+// List of permission strings based on [1] and [2].  See |kSafePermissionDicts|
+// for permission dicts.  Since Public Session users may be fully unaware of any
+// apps being installed, their consent to access any kind of sensitive
+// information cannot be assumed.  Therefore only APIs are whitelisted which
+// should not leak sensitive data to the caller.  Since the privacy boundary is
+// drawn at the API level, no safeguards are required to prevent exfiltration
+// and thus apps may communicate freely over any kind of network.
 // [1] https://developer.chrome.com/apps/declare_permissions
 // [2] https://developer.chrome.com/apps/api_other
-const char* const kSafePermissions[] = {
+const char* const kSafePermissionStrings[] = {
     // Risky: Reading accessibility settings could allow to infer health
     // information.
     // "accessibilityFeatures.read",
@@ -310,9 +310,6 @@
     "overrideEscFullscreen",
 
     // TBD
-    // "fileSystem",
-
-    // TBD
     // "fileSystemProvider",
 
     // Just another type of connectivity.  On the system side, no user data is
@@ -356,12 +353,6 @@
     // is stored on a serial device and being read without the user's consent.
     "serial",
 
-    // Just another type of connectivity.
-    "socket",
-
-    // Just another type of connectivity.
-    "sockets",
-
     // Per-app sandbox.  User cannot log into Public Session, thus storage
     // cannot be sync'ed to the cloud.
     "storage",
@@ -403,6 +394,16 @@
     "webview",
 };
 
+// Some permissions take the form of a dictionary.  See |kSafePermissionStrings|
+// for permission strings (and for more documentation).
+const char* const kSafePermissionDicts[] = {
+    // TBD
+    // "fileSystem",
+
+    // Just another type of connectivity.
+    "socket",
+};
+
 // Return true iff |entry| is contained in |char_array|.
 bool ArrayContainsImpl(const char* const char_array[],
                        size_t entry_count,
@@ -426,7 +427,7 @@
 // Returns true for platform apps that are considered safe for Public Sessions,
 // which among other things requires the manifest top-level entries to be
 // contained in the |kSafeManifestEntries| whitelist and all permissions to be
-// contained in |kSafePermissions|.
+// contained in |kSafePermissionStrings| or |kSafePermissionDicts|.
 bool IsPlatformAppSafeForPublicSession(const extensions::Extension* extension) {
   if (extension->GetType() != extensions::Manifest::TYPE_PLATFORM_APP) {
     LOG(ERROR) << extension->id() << " is not a platform app.";
@@ -439,22 +440,45 @@
       continue;
     }
 
-    // Permissions must be whitelisted in |kSafePermissions|.
+    // Permissions must be whitelisted in |kSafePermissionStrings| or
+    // |kSafePermissionDicts|.
     if (it.key() == emk::kPermissions ||
         it.key() == emk::kOptionalPermissions) {
       const base::ListValue* list_value;
       if (!it.value().GetAsList(&list_value)) {
-        LOG(ERROR) << it.key() << " is not a list.";
+        LOG(ERROR) << extension->id() << ": " << it.key() << " is not a list.";
         return false;
       }
       for (auto it2 = list_value->begin(); it2 != list_value->end(); ++it2) {
+        // Try to read as dictionary.
+        const base::DictionaryValue *dict_value;
+        if ((*it2)->GetAsDictionary(&dict_value)) {
+          if (dict_value->size() != 1) {
+            LOG(ERROR) << extension->id()
+                       << " has dict in permission list with size "
+                       << dict_value->size() << ".";
+            return false;
+          }
+          for (base::DictionaryValue::Iterator it3(*dict_value);
+               !it3.IsAtEnd(); it3.Advance()) {
+            if (!ArrayContains(kSafePermissionDicts, it3.key())) {
+              LOG(ERROR) << extension->id()
+                         << " has non-whitelisted dict in permission list: "
+                         << it3.key();
+              return false;
+            }
+          }
+          continue;
+        }
+        // Try to read as string.
         std::string permission_string;
         if (!(*it2)->GetAsString(&permission_string)) {
-          LOG(ERROR) << it.key() << " contains a non-string.";
+          LOG(ERROR) << extension->id() << ": " << it.key()
+                     << " contains a token that's neither a string nor a dict.";
           return false;
         }
         // Accept whitelisted permissions.
-        if (ArrayContains(kSafePermissions, permission_string)) {
+        if (ArrayContains(kSafePermissionStrings, permission_string)) {
           continue;
         }
         // Allow arbitrary web requests.  Don't include <all_urls> because that
@@ -473,7 +497,7 @@
     } else if (it.key() == emk::kApp) {
       const base::DictionaryValue *dict_value;
       if (!it.value().GetAsDictionary(&dict_value)) {
-        LOG(ERROR) << extension->id() << " app is not a dictionary.";
+        LOG(ERROR) << extension->id() << ": app is not a dictionary.";
         return false;
       }
       for (base::DictionaryValue::Iterator it2(*dict_value);
@@ -485,12 +509,11 @@
           return false;
         }
       }
-    // Require v2 because that's the only version
-    // IsPlatformAppSafeForPublicSession() understands.
+    // Require v2 because that's the only version we understand.
     } else if (it.key() == emk::kManifestVersion) {
       int version;
       if (!it.value().GetAsInteger(&version)) {
-        LOG(ERROR) << extension->id() << " " << emk::kManifestVersion
+        LOG(ERROR) << extension->id() << ": " << emk::kManifestVersion
                    << " is not an integer.";
         return false;
       }
diff --git a/chrome/browser/chromeos/extensions/device_local_account_management_policy_provider_unittest.cc b/chrome/browser/chromeos/extensions/device_local_account_management_policy_provider_unittest.cc
index b7e95e3..d428bf5d 100644
--- a/chrome/browser/chromeos/extensions/device_local_account_management_policy_provider_unittest.cc
+++ b/chrome/browser/chromeos/extensions/device_local_account_management_policy_provider_unittest.cc
@@ -377,6 +377,52 @@
     EXPECT_NE(base::string16(), error);
     error.clear();
   }
+
+  // Verify that a platform app with socket dictionary permission can be
+  // installed.
+  {
+    base::DictionaryValue* const socket = new base::DictionaryValue();
+    base::ListValue* const tcp_list = new base::ListValue();
+    tcp_list->AppendString("tcp-connect");
+    socket->Set("socket", tcp_list);
+    base::ListValue* const permissions = new base::ListValue();
+    permissions->Append(socket);
+    base::DictionaryValue values;
+    values.Set(extensions::manifest_keys::kPermissions, permissions);
+
+    extension = CreatePlatformAppWithExtraValues(
+        &values,
+        extensions::Manifest::EXTERNAL_POLICY,
+        extensions::Extension::NO_FLAGS);
+    ASSERT_TRUE(extension);
+
+    EXPECT_TRUE(provider.UserMayLoad(extension.get(), &error));
+    EXPECT_EQ(base::string16(), error);
+    error.clear();
+  }
+
+  // Verify that a platform app with unknown dictionary permission cannot be
+  // installed.
+  {
+    base::DictionaryValue* const socket = new base::DictionaryValue();
+    base::ListValue* const tcp_list = new base::ListValue();
+    tcp_list->AppendString("unknown_value");
+    socket->Set("unknown_key", tcp_list);
+    base::ListValue* const permissions = new base::ListValue();
+    permissions->Append(socket);
+    base::DictionaryValue values;
+    values.Set(extensions::manifest_keys::kPermissions, permissions);
+
+    extension = CreatePlatformAppWithExtraValues(
+        &values,
+        extensions::Manifest::EXTERNAL_POLICY,
+        extensions::Extension::NO_FLAGS);
+    ASSERT_TRUE(extension);
+
+    EXPECT_FALSE(provider.UserMayLoad(extension.get(), &error));
+    EXPECT_NE(base::string16(), error);
+    error.clear();
+  }
 }
 
 TEST(DeviceLocalAccountManagementPolicyProviderTest, KioskAppSession) {
diff --git a/chrome/browser/engagement/site_engagement_service.cc b/chrome/browser/engagement/site_engagement_service.cc
index dbd4db73..1133fe8 100644
--- a/chrome/browser/engagement/site_engagement_service.cc
+++ b/chrome/browser/engagement/site_engagement_service.cc
@@ -228,6 +228,14 @@
   last_engagement_time_ = now;
 }
 
+void SiteEngagementScore::Reset(double points) {
+  raw_score_ = points;
+  points_added_today_ = 0;
+
+  // This must be set in order to prevent the score from decaying when read.
+  last_engagement_time_ = clock_->Now();
+}
+
 bool SiteEngagementScore::MaxPointsPerDayAdded() {
   if (!last_engagement_time_.is_null() &&
       clock_->Now().LocalMidnight() != last_engagement_time_.LocalMidnight()) {
@@ -379,6 +387,25 @@
   RecordMetrics();
 }
 
+void SiteEngagementService::ResetScoreForURL(const GURL& url, double score) {
+  DCHECK(url.is_valid());
+  DCHECK_GE(score, 0);
+  DCHECK_LE(score, SiteEngagementScore::kMaxPoints);
+
+  HostContentSettingsMap* settings_map =
+    HostContentSettingsMapFactory::GetForProfile(profile_);
+  scoped_ptr<base::DictionaryValue> score_dict =
+      GetScoreDictForOrigin(settings_map, url);
+  SiteEngagementScore engagement_score(clock_.get(), *score_dict);
+
+  engagement_score.Reset(score);
+  if (engagement_score.UpdateScoreDict(score_dict.get())) {
+    settings_map->SetWebsiteSettingDefaultScope(
+        url, GURL(), CONTENT_SETTINGS_TYPE_SITE_ENGAGEMENT, std::string(),
+        score_dict.release());
+  }
+}
+
 void SiteEngagementService::OnURLsDeleted(
     history::HistoryService* history_service,
     bool all_history,
diff --git a/chrome/browser/engagement/site_engagement_service.h b/chrome/browser/engagement/site_engagement_service.h
index 53ad612..fe75f74d 100644
--- a/chrome/browser/engagement/site_engagement_service.h
+++ b/chrome/browser/engagement/site_engagement_service.h
@@ -84,6 +84,9 @@
   double Score() const;
   void AddPoints(double points);
 
+  // Resets the score to |points| and reset the daily point limit.
+  void Reset(double points);
+
   // Returns true if the maximum number of points today has been added.
   bool MaxPointsPerDayAdded();
 
@@ -100,6 +103,7 @@
  private:
   FRIEND_TEST_ALL_PREFIXES(SiteEngagementScoreTest, PartiallyEmptyDictionary);
   FRIEND_TEST_ALL_PREFIXES(SiteEngagementScoreTest, PopulatedDictionary);
+  FRIEND_TEST_ALL_PREFIXES(SiteEngagementScoreTest, Reset);
   friend class SiteEngagementScoreTest;
 
   // Array holding the values corresponding to each item in Variation array.
@@ -181,19 +185,22 @@
   // Returns a map of all stored origins and their engagement scores.
   std::map<GURL, double> GetScoreMap();
 
-  // Update the karma score of the origin matching |url| for navigation.
+  // Update the engagement score of the origin matching |url| for navigation.
   void HandleNavigation(const GURL& url, ui::PageTransition transition);
 
-  // Update the karma score of the origin matching |url| for time-on-site, based
-  // on user input.
+  // Update the engagement score of the origin matching |url| for time-on-site,
+  // based on user input.
   void HandleUserInput(const GURL& url,
                        SiteEngagementMetrics::EngagementType type);
 
-  // Update the karma score of the origin matching |url| for media playing. The
-  // points awarded are discounted if the media is being played in a non-visible
-  // tab.
+  // Update the engagement score of the origin matching |url| for media playing.
+  // The points awarded are discounted if the media is being played in a non-
+  // visible tab.
   void HandleMediaPlaying(const GURL& url, bool is_hidden);
 
+  // Resets the engagement score |url| to |score|, clearing daily limits.
+  void ResetScoreForURL(const GURL& url, double score);
+
   // Overridden from history::HistoryServiceObserver:
   void OnURLsDeleted(history::HistoryService* history_service,
                      bool all_history,
diff --git a/chrome/browser/engagement/site_engagement_service_unittest.cc b/chrome/browser/engagement/site_engagement_service_unittest.cc
index a703609c..5a57d28 100644
--- a/chrome/browser/engagement/site_engagement_service_unittest.cc
+++ b/chrome/browser/engagement/site_engagement_service_unittest.cc
@@ -370,6 +370,33 @@
   TestScoreInitializesAndUpdates(&dict, 1, 2, GetReferenceTime());
 }
 
+// Test that resetting a score has the correct properties.
+TEST_F(SiteEngagementScoreTest, Reset) {
+  base::Time current_day = GetReferenceTime();
+
+  test_clock_.SetNow(current_day);
+  score_.AddPoints(SiteEngagementScore::GetNavigationPoints());
+  EXPECT_EQ(SiteEngagementScore::GetNavigationPoints(), score_.Score());
+
+  current_day += base::TimeDelta::FromDays(7);
+  test_clock_.SetNow(current_day);
+
+  score_.Reset(20.0);
+  EXPECT_DOUBLE_EQ(20.0, score_.Score());
+  EXPECT_DOUBLE_EQ(0, score_.points_added_today_);
+  EXPECT_EQ(current_day, score_.last_engagement_time_);
+
+  // Adding points after the reset should work as normal.
+  score_.AddPoints(5);
+  EXPECT_EQ(25.0, score_.Score());
+
+  // The decay should happen one decay period from
+  test_clock_.SetNow(current_day +
+                     base::TimeDelta::FromDays(
+                         SiteEngagementScore::GetDecayPeriodInDays() + 1));
+  EXPECT_EQ(25.0 - SiteEngagementScore::GetDecayPoints(), score_.Score());
+}
+
 class SiteEngagementServiceTest : public ChromeRenderViewHostTestHarness {
  public:
   void SetUp() override {
diff --git a/chrome/browser/extensions/api/bookmarks/bookmarks_api.cc b/chrome/browser/extensions/api/bookmarks/bookmarks_api.cc
index 4c4112d..4943632f 100644
--- a/chrome/browser/extensions/api/bookmarks/bookmarks_api.cc
+++ b/chrome/browser/extensions/api/bookmarks/bookmarks_api.cc
@@ -52,10 +52,6 @@
 #include "extensions/browser/notification_types.h"
 #include "ui/base/l10n/l10n_util.h"
 
-#if defined(OS_WIN)
-#include "ui/aura/remote_window_tree_host_win.h"
-#endif
-
 using bookmarks::BookmarkModel;
 using bookmarks::BookmarkNode;
 using bookmarks::ManagedBookmarkService;
@@ -798,11 +794,6 @@
   gfx::NativeWindow owning_window = web_contents ?
       platform_util::GetTopLevel(web_contents->GetNativeView())
           : NULL;
-#if defined(OS_WIN)
-  if (!owning_window &&
-      chrome::GetActiveDesktop() == chrome::HOST_DESKTOP_TYPE_ASH)
-    owning_window = aura::RemoteWindowTreeHostWin::Instance()->GetAshWindow();
-#endif
   // |web_contents| can be NULL (for background pages), which is fine. In such
   // a case if file-selection dialogs are forbidden by policy, we will not
   // show an InfoBar, which is better than letting one appear out of the blue.
diff --git a/chrome/browser/metro_viewer/DEPS b/chrome/browser/metro_viewer/DEPS
deleted file mode 100644
index 4199b39..0000000
--- a/chrome/browser/metro_viewer/DEPS
+++ /dev/null
@@ -1,3 +0,0 @@
-include_rules = [
-  "+win8/viewer",
-]
diff --git a/chrome/browser/metro_viewer/OWNERS b/chrome/browser/metro_viewer/OWNERS
deleted file mode 100644
index b81e28b..0000000
--- a/chrome/browser/metro_viewer/OWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
-ananta@chromium.org
-cpu@chromium.org
-scottmg@chromium.org
diff --git a/chrome/browser/metro_viewer/chrome_metro_viewer_process_host_aurawin.cc b/chrome/browser/metro_viewer/chrome_metro_viewer_process_host_aurawin.cc
deleted file mode 100644
index 1c993f87..0000000
--- a/chrome/browser/metro_viewer/chrome_metro_viewer_process_host_aurawin.cc
+++ /dev/null
@@ -1,174 +0,0 @@
-// Copyright 2012 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/metro_viewer/chrome_metro_viewer_process_host_aurawin.h"
-
-#include "ash/display/display_info.h"
-#include "ash/display/display_manager.h"
-#include "ash/host/ash_remote_window_tree_host_win.h"
-#include "ash/shell.h"
-#include "ash/wm/window_positioner.h"
-#include "base/logging.h"
-#include "base/memory/ref_counted.h"
-#include "base/strings/stringprintf.h"
-#include "chrome/browser/browser_process.h"
-#include "chrome/browser/browser_process_platform_part_aurawin.h"
-#include "chrome/browser/browser_shutdown.h"
-#include "chrome/browser/chrome_notification_types.h"
-#include "chrome/browser/lifetime/application_lifetime.h"
-#include "chrome/browser/profiles/profile_manager.h"
-#include "chrome/browser/search_engines/template_url_service_factory.h"
-#include "chrome/browser/ui/ash/ash_init.h"
-#include "chrome/browser/ui/browser.h"
-#include "chrome/browser/ui/browser_list.h"
-#include "chrome/browser/ui/browser_navigator.h"
-#include "chrome/browser/ui/browser_navigator_params.h"
-#include "chrome/browser/ui/browser_window.h"
-#include "chrome/browser/ui/host_desktop.h"
-#include "chrome/browser/ui/tabs/tab_strip_model.h"
-#include "chrome/common/env_vars.h"
-#include "components/search_engines/util.h"
-#include "content/public/browser/browser_thread.h"
-#include "content/public/browser/gpu_data_manager.h"
-#include "content/public/browser/notification_service.h"
-#include "content/public/browser/page_navigator.h"
-#include "content/public/browser/web_contents.h"
-#include "ui/aura/remote_window_tree_host_win.h"
-#include "ui/gfx/win/dpi.h"
-#include "ui/metro_viewer/metro_viewer_messages.h"
-#include "url/gurl.h"
-
-namespace {
-
-void CloseOpenAshBrowsers() {
-  BrowserList* browser_list =
-      BrowserList::GetInstance(chrome::HOST_DESKTOP_TYPE_ASH);
-  if (browser_list) {
-    for (BrowserList::const_iterator i = browser_list->begin();
-         i != browser_list->end(); ++i) {
-      Browser* browser = *i;
-      browser->window()->Close();
-      // If the attempt to Close the browser fails due to unload handlers on
-      // the page or in progress downloads, etc, destroy all tabs on the page.
-      while (browser->tab_strip_model()->count())
-        delete browser->tab_strip_model()->GetWebContentsAt(0);
-    }
-  }
-}
-
-void OpenURL(const GURL& url) {
-  chrome::NavigateParams params(
-      ProfileManager::GetActiveUserProfile(),
-      GURL(url),
-      ui::PAGE_TRANSITION_TYPED);
-  params.disposition = NEW_FOREGROUND_TAB;
-  params.host_desktop_type = chrome::HOST_DESKTOP_TYPE_ASH;
-  chrome::Navigate(&params);
-}
-
-}  // namespace
-
-ChromeMetroViewerProcessHost::ChromeMetroViewerProcessHost()
-    : MetroViewerProcessHost(
-          content::BrowserThread::GetMessageLoopProxyForThread(
-              content::BrowserThread::IO)) {
-  chrome::IncrementKeepAliveCount();
-}
-
-ChromeMetroViewerProcessHost::~ChromeMetroViewerProcessHost() {
-}
-
-void ChromeMetroViewerProcessHost::OnChannelError() {
-  // TODO(cpu): At some point we only close the browser. Right now this
-  // is very convenient for developing.
-  DVLOG(1) << "viewer channel error : Quitting browser";
-
-  // Unset environment variable to let breakpad know that metro process wasn't
-  // connected.
-  ::SetEnvironmentVariableA(env_vars::kMetroConnected, NULL);
-
-  // It seems possible that channel is connected, but ASH desktop is not yet
-  // created (instance is still NULL) and we receive channel error.
-  if (aura::RemoteWindowTreeHostWin::Instance()) {
-    aura::RemoteWindowTreeHostWin::Instance()->Disconnected();
-
-    chrome::DecrementKeepAliveCount();
-
-    // If browser is trying to quit, we shouldn't reenter the process.
-    // TODO(shrikant): In general there seem to be issues with how AttemptExit
-    // reentry works. In future release please clean up related code.
-    if (!browser_shutdown::IsTryingToQuit()) {
-      CloseOpenAshBrowsers();
-      chrome::CloseAsh();
-    }
-    // Tell the rest of Chrome about it.
-    content::NotificationService::current()->Notify(
-        chrome::NOTIFICATION_ASH_SESSION_ENDED,
-        content::NotificationService::AllSources(),
-        content::NotificationService::NoDetails());
-    return;
-  }
-
-  chrome::DecrementKeepAliveCount();
-
-  // This will delete the MetroViewerProcessHost object. Don't access member
-  // variables/functions after this call.
-  g_browser_process->platform_part()->OnMetroViewerProcessTerminated();
-}
-
-void ChromeMetroViewerProcessHost::OnChannelConnected(int32_t /*peer_pid*/) {
-  DVLOG(1) << "ChromeMetroViewerProcessHost::OnChannelConnected: ";
-  // Set environment variable to let breakpad know that metro process was
-  // connected.
-  ::SetEnvironmentVariableA(env_vars::kMetroConnected, "1");
-}
-
-void ChromeMetroViewerProcessHost::OnSetTargetSurface(
-    gfx::NativeViewId target_surface,
-    float device_scale) {
-  HWND hwnd = reinterpret_cast<HWND>(target_surface);
-
-  gfx::SetDefaultDeviceScaleFactor(device_scale);
-  chrome::OpenAsh(hwnd);
-  DCHECK(aura::RemoteWindowTreeHostWin::Instance());
-  DCHECK_EQ(hwnd, aura::RemoteWindowTreeHostWin::Instance()->remote_window());
-  ash::Shell::GetInstance()->CreateShelf();
-  ash::Shell::GetInstance()->ShowShelf();
-
-  // Tell our root window host that the viewer has connected.
-  aura::RemoteWindowTreeHostWin::Instance()->Connected(this);
-
-  // On Windows 8 ASH we default to SHOW_STATE_MAXIMIZED for the browser
-  // window. This is to ensure that we honor metro app conventions by default.
-  ash::WindowPositioner::SetMaximizeFirstWindow(true);
-  // Tell the rest of Chrome that Ash is running.
-  content::NotificationService::current()->Notify(
-      chrome::NOTIFICATION_ASH_SESSION_STARTED,
-      content::NotificationService::AllSources(),
-      content::NotificationService::NoDetails());
-}
-
-void ChromeMetroViewerProcessHost::OnOpenURL(const base::string16& url) {
-  OpenURL(GURL(url));
-}
-
-void ChromeMetroViewerProcessHost::OnHandleSearchRequest(
-    const base::string16& search_string) {
-  GURL url(GetDefaultSearchURLForSearchTerms(
-      TemplateURLServiceFactory::GetForProfile(
-          ProfileManager::GetActiveUserProfile()), search_string));
-  if (url.is_valid())
-    OpenURL(url);
-}
-
-void ChromeMetroViewerProcessHost::OnWindowSizeChanged(uint32_t width,
-                                                       uint32_t height) {
-  std::vector<ash::DisplayInfo> info_list;
-  info_list.push_back(ash::DisplayInfo::CreateFromSpec(
-      base::StringPrintf("%dx%d*%f", width, height, gfx::GetDPIScale())));
-  ash::Shell::GetInstance()->display_manager()->OnNativeDisplaysChanged(
-      info_list);
-  aura::RemoteWindowTreeHostWin::Instance()->HandleWindowSizeChanged(width,
-                                                                     height);
-}
diff --git a/chrome/browser/metro_viewer/chrome_metro_viewer_process_host_aurawin.h b/chrome/browser/metro_viewer/chrome_metro_viewer_process_host_aurawin.h
deleted file mode 100644
index 9696a490..0000000
--- a/chrome/browser/metro_viewer/chrome_metro_viewer_process_host_aurawin.h
+++ /dev/null
@@ -1,37 +0,0 @@
-// Copyright 2012 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_METRO_VIEWER_CHROME_METRO_VIEWER_PROCESS_HOST_AURAWIN_H_
-#define CHROME_BROWSER_METRO_VIEWER_CHROME_METRO_VIEWER_PROCESS_HOST_AURAWIN_H_
-
-#include <stdint.h>
-
-#include "base/macros.h"
-#include "win8/viewer/metro_viewer_process_host.h"
-
-namespace base {
-class FilePath;
-}
-
-class ChromeMetroViewerProcessHost : public win8::MetroViewerProcessHost {
- public:
-  ChromeMetroViewerProcessHost();
-  ~ChromeMetroViewerProcessHost() override;
-
- private:
-  // win8::MetroViewerProcessHost implementation
-  void OnChannelError() override;
-
-  // IPC::Listener implementation
-  void OnChannelConnected(int32_t peer_pid) override;
-  void OnSetTargetSurface(gfx::NativeViewId target_surface,
-                          float device_scale) override;
-  void OnOpenURL(const base::string16& url) override;
-  void OnHandleSearchRequest(const base::string16& search_string) override;
-  void OnWindowSizeChanged(uint32_t width, uint32_t height) override;
-
-  DISALLOW_COPY_AND_ASSIGN(ChromeMetroViewerProcessHost);
-};
-
-#endif  // CHROME_BROWSER_METRO_VIEWER_CHROME_METRO_VIEWER_PROCESS_HOST_AURAWIN_H_
diff --git a/chrome/browser/permissions/permission_uma_util.cc b/chrome/browser/permissions/permission_uma_util.cc
index 439ca44..133904df 100644
--- a/chrome/browser/permissions/permission_uma_util.cc
+++ b/chrome/browser/permissions/permission_uma_util.cc
@@ -185,33 +185,6 @@
                                   std::move(sample));
 }
 
-std::string PermissionTypeToString(PermissionType permission_type) {
-  switch (permission_type) {
-    case PermissionType::MIDI_SYSEX:
-      return "MidiSysex";
-    case PermissionType::PUSH_MESSAGING:
-      return "PushMessaging";
-    case PermissionType::NOTIFICATIONS:
-      return "Notifications";
-    case PermissionType::GEOLOCATION:
-      return "Geolocation";
-    case PermissionType::PROTECTED_MEDIA_IDENTIFIER:
-      return "ProtectedMediaIdentifier";
-    case PermissionType::DURABLE_STORAGE:
-      return "DurableStorage";
-    case PermissionType::MIDI:
-      return "Midi";
-    case PermissionType::AUDIO_CAPTURE:
-      return "AudioRecording";
-    case PermissionType::VIDEO_CAPTURE:
-      return "VideoRecording";
-    case PermissionType::NUM:
-      break;
-  }
-  NOTREACHED();
-  return std::string();
-}
-
 void RecordPermissionRequest(PermissionType permission,
                              const GURL& requesting_origin,
                              const GURL& embedding_origin,
@@ -259,7 +232,7 @@
 
     base::HistogramBase* histogram = base::LinearHistogram::FactoryGet(
         "Permissions.Requested.CrossOrigin_" +
-            PermissionTypeToString(permission),
+            PermissionUtil::GetPermissionString(permission),
         1, content::PERMISSION_STATUS_LAST, content::PERMISSION_STATUS_LAST + 1,
         base::HistogramBase::kUmaTargetedHistogramFlag);
     histogram->Add(embedding_permission_status);
diff --git a/chrome/browser/plugins/plugin_infobar_delegates.cc b/chrome/browser/plugins/plugin_infobar_delegates.cc
index fc2bb13..09df300 100644
--- a/chrome/browser/plugins/plugin_infobar_delegates.cc
+++ b/chrome/browser/plugins/plugin_infobar_delegates.cc
@@ -38,10 +38,6 @@
 #if defined(OS_WIN)
 #include <shellapi.h>
 #include "ui/base/win/shell.h"
-
-#if defined(USE_AURA)
-#include "ui/aura/remote_window_tree_host_win.h"
-#endif
 #endif
 
 using base::UserMetricsAction;
diff --git a/chrome/browser/profiles/profile_manager_browsertest.cc b/chrome/browser/profiles/profile_manager_browsertest.cc
index e7020ed..0c5a0651 100644
--- a/chrome/browser/profiles/profile_manager_browsertest.cc
+++ b/chrome/browser/profiles/profile_manager_browsertest.cc
@@ -134,7 +134,7 @@
 #endif
 }
 
-} // namespace
+}  // namespace
 
 // This file contains tests for the ProfileManager that require a heavyweight
 // InProcessBrowserTest.  These include tests involving profile deletion.
@@ -273,8 +273,8 @@
   // Create a profile, make sure callback is invoked before any callbacks are
   // invoked (so they can do things like sign in the profile, etc).
   ProfileManager::CreateMultiProfileAsync(
-      base::string16(), // name
-      std::string(), // icon url
+      base::string16(),  // name
+      std::string(),  // icon url
       base::Bind(ProfileCreationComplete),
       std::string());
   // Wait for profile to finish loading.
@@ -466,3 +466,31 @@
   EXPECT_EQ(0u, verify_delete.GetPasswords().size());
 }
 #endif  // !defined(OS_WIN) && !defined(OS_ANDROID) && !defined(OS_CHROMEOS)
+
+// Tests Profile::HasOffTheRecordProfile, Profile::IsValidProfile and the
+// profile counts in ProfileManager with respect to the creation and destruction
+// of incognito profiles.
+IN_PROC_BROWSER_TEST_F(ProfileManagerBrowserTest, IncognitoProfile) {
+  ProfileManager* profile_manager = g_browser_process->profile_manager();
+  ASSERT_TRUE(profile_manager);
+
+  Profile* profile = ProfileManager::GetActiveUserProfile();
+  ASSERT_TRUE(profile);
+  EXPECT_FALSE(profile->HasOffTheRecordProfile());
+
+  size_t initial_profile_count = profile_manager->GetNumberOfProfiles();
+
+  // Create an incognito profile.
+  Profile* incognito_profile = profile->GetOffTheRecordProfile();
+
+  EXPECT_TRUE(profile->HasOffTheRecordProfile());
+  ASSERT_TRUE(profile_manager->IsValidProfile(incognito_profile));
+  EXPECT_EQ(initial_profile_count, profile_manager->GetNumberOfProfiles());
+
+  // Delete the incognito profile.
+  incognito_profile->GetOriginalProfile()->DestroyOffTheRecordProfile();
+
+  EXPECT_FALSE(profile->HasOffTheRecordProfile());
+  EXPECT_FALSE(profile_manager->IsValidProfile(incognito_profile));
+  EXPECT_EQ(initial_profile_count, profile_manager->GetNumberOfProfiles());
+}
diff --git a/chrome/browser/resources/engagement/engagement_table.css b/chrome/browser/resources/engagement/engagement_table.css
index cb6a0088..e35c71a 100644
--- a/chrome/browser/resources/engagement/engagement_table.css
+++ b/chrome/browser/resources/engagement/engagement_table.css
@@ -34,3 +34,10 @@
 :host([sort-reverse]) .sort-column::after {
   content: 'â–¼';
 }
+
+paper-slider {
+  width: 300px;
+  --paper-slider-input: {
+    width: 70px;
+  };
+}
diff --git a/chrome/browser/resources/engagement/engagement_table.html b/chrome/browser/resources/engagement/engagement_table.html
index 3b667e8..3beb8e620 100644
--- a/chrome/browser/resources/engagement/engagement_table.html
+++ b/chrome/browser/resources/engagement/engagement_table.html
@@ -1,4 +1,5 @@
 <link rel="import" href="chrome://resources/polymer/v1_0/polymer/polymer.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/paper-slider/paper-slider.html">
 
 <dom-module id="engagement-table">
   <link rel="import" type="css" href="engagement_table.css">
@@ -20,7 +21,11 @@
                   sort="[[getTableSortFunction_(sortKey_, sortReverse)]]">
           <tr>
             <td class="origin-cell">{{info.origin}}</td>
-            <td>{{info.score}}</td>
+            <td>
+              <paper-slider step="0.1" min="0" max="100" value="[[info.score]]"
+                            editable on-change="scoreChanged"
+                            noink></paper-slider>
+            </td>
           </tr>
         </template>
       </tbody>
diff --git a/chrome/browser/resources/engagement/engagement_table.js b/chrome/browser/resources/engagement/engagement_table.js
index 976fbe97..b8a7397 100644
--- a/chrome/browser/resources/engagement/engagement_table.js
+++ b/chrome/browser/resources/engagement/engagement_table.js
@@ -104,4 +104,20 @@
     assertNotReached('Unsupported sort key: ' + sortKey);
     return 0;
   },
+
+  /**
+   * Handles a score input change by firing an event that contains the origin
+   * changed and its new score.
+   * @param {Event} e The change event for the score input.
+   */
+  scoreChanged: function(e) {
+    if (e.target.value == '')
+      return;
+
+    e.model.set('info.score', Number(e.target.value));
+    this.fire('score-edited', {
+      origin: e.model.get('info.origin'),
+      score: Number(e.target.value)
+    });
+  }
 });
diff --git a/chrome/browser/resources/engagement/site_engagement.html b/chrome/browser/resources/engagement/site_engagement.html
index 3d659b2..cef7e16 100644
--- a/chrome/browser/resources/engagement/site_engagement.html
+++ b/chrome/browser/resources/engagement/site_engagement.html
@@ -8,6 +8,12 @@
   <link rel="stylesheet" href="chrome://resources/css/text_defaults.css">
   <script src="chrome://resources/js/util.js"></script>
   <script src="chrome://site-engagement/site_engagement.js"></script>
+  <style>
+    body {
+      font-family: 'Roboto', 'Noto', sans-serif;
+      font-size: 14px;
+    }
+  </style>
 </head>
 <body>
   <h1>Site Engagement</h1>
diff --git a/chrome/browser/resources/engagement/site_engagement.js b/chrome/browser/resources/engagement/site_engagement.js
index 3845129..b13ff7e 100644
--- a/chrome/browser/resources/engagement/site_engagement.js
+++ b/chrome/browser/resources/engagement/site_engagement.js
@@ -15,6 +15,16 @@
             siteEngagementMojom.SiteEngagementUIHandler.name),
         siteEngagementMojom.SiteEngagementUIHandler);
 
+    var engagementTable = $('engagement-table');
+    var updateInterval = null;
+
+    engagementTable.addEventListener('score-edited', function(e) {
+      var detail = e.detail;
+      uiHandler.setSiteEngagementScoreForOrigin(detail.origin, detail.score);
+      clearInterval(updateInterval);
+      updateInterval = setInterval(updateEngagementTable, 5000);
+    });
+
     var updateEngagementTable = function() {
       // Populate engagement table.
       uiHandler.getSiteEngagementInfo().then(function(response) {
@@ -22,11 +32,11 @@
         response.info.forEach(function(x) {
           x.score = Number(Math.round(x.score * 100) / 100);
         });
-        $('engagement-table').engagementInfo = response.info;
+        engagementTable.engagementInfo = response.info;
       });
 
-      setTimeout(updateEngagementTable, 2000);
     };
     updateEngagementTable();
+    updateInterval = setInterval(updateEngagementTable, 5000);
   };
 });
diff --git a/chrome/browser/safe_browsing/protocol_manager.cc b/chrome/browser/safe_browsing/protocol_manager.cc
index f56103ff..4d04f67 100644
--- a/chrome/browser/safe_browsing/protocol_manager.cc
+++ b/chrome/browser/safe_browsing/protocol_manager.cc
@@ -444,6 +444,8 @@
 
   if (it != hash_requests_.end()) {
     // GetHash response.
+    // Reset the scoped pointer so the fetcher gets destroyed properly.
+    fetcher.reset(it->first);
     RecordHttpResponseOrErrorCode(kGetHashUmaResponseMetricName, status,
                                   response_code);
     const FullHashDetails& details = it->second;
@@ -492,6 +494,9 @@
     // V4 FindFullHashes response.
     // TODO(kcarattini): Consider pulling all the V4 handling out into a
     // separate V4ProtocolManager class.
+
+    // Reset the scoped pointer so the fetcher gets destroyed properly.
+    fetcher.reset(v4_it->first);
     RecordHttpResponseOrErrorCode(kUmaV4ResponseMetricName, status,
                                   response_code);
     const FullHashDetails& details = v4_it->second;
diff --git a/chrome/browser/safe_browsing/protocol_manager.h b/chrome/browser/safe_browsing/protocol_manager.h
index 8d3c1191..c50ac2a8 100644
--- a/chrome/browser/safe_browsing/protocol_manager.h
+++ b/chrome/browser/safe_browsing/protocol_manager.h
@@ -224,6 +224,12 @@
                            TestGetHashBackOffTimes);
   FRIEND_TEST_ALL_PREFIXES(SafeBrowsingProtocolManagerTest,
                            TestGetV4HashBackOffTimes);
+  FRIEND_TEST_ALL_PREFIXES(SafeBrowsingProtocolManagerTest,
+                           TestGetV4HashErrorHandlingOK);
+  FRIEND_TEST_ALL_PREFIXES(SafeBrowsingProtocolManagerTest,
+                           TestGetV4HashErrorHandlingNetwork);
+  FRIEND_TEST_ALL_PREFIXES(SafeBrowsingProtocolManagerTest,
+                           TestGetV4HashErrorHandlingResponseCode);
   FRIEND_TEST_ALL_PREFIXES(SafeBrowsingProtocolManagerTest, TestNextChunkUrl);
   FRIEND_TEST_ALL_PREFIXES(SafeBrowsingProtocolManagerTest, TestUpdateUrl);
   friend class SafeBrowsingServerTest;
diff --git a/chrome/browser/safe_browsing/protocol_manager_unittest.cc b/chrome/browser/safe_browsing/protocol_manager_unittest.cc
index b670f51a..87b8dff 100644
--- a/chrome/browser/safe_browsing/protocol_manager_unittest.cc
+++ b/chrome/browser/safe_browsing/protocol_manager_unittest.cc
@@ -122,8 +122,128 @@
     EXPECT_EQ("", url_fetcher->upload_data());
     EXPECT_EQ(GURL(expected_url), url_fetcher->GetOriginalURL());
   }
+
+  std::string GetStockV4HashResponse() {
+    FindFullHashesResponse res;
+    res.mutable_negative_cache_duration()->set_seconds(600);
+    ThreatMatch* m = res.add_matches();
+    m->set_threat_type(API_ABUSE);
+    m->set_platform_type(CHROME_PLATFORM);
+    m->set_threat_entry_type(URL_EXPRESSION);
+    m->mutable_cache_duration()->set_seconds(300);
+    m->mutable_threat()->set_hash(SBFullHashToString(
+        SBFullHashForString("Everything's shiny, Cap'n.")));
+    ThreatEntryMetadata::MetadataEntry* e =
+        m->mutable_threat_entry_metadata()->add_entries();
+    e->set_key("permission");
+    e->set_value("NOTIFICATIONS");
+
+    // Serialize.
+    std::string res_data;
+    res.SerializeToString(&res_data);
+
+    return res_data;
+  }
 };
 
+void ValidateGetV4HashResults(
+    const std::vector<SBFullHashResult>& expected_full_hashes,
+    const base::TimeDelta& expected_cache_duration,
+    const std::vector<SBFullHashResult>& full_hashes,
+    const base::TimeDelta& cache_duration) {
+  EXPECT_EQ(expected_cache_duration, cache_duration);
+  ASSERT_EQ(expected_full_hashes.size(), full_hashes.size());
+
+  for (unsigned int i = 0; i < expected_full_hashes.size(); ++i) {
+    const SBFullHashResult& expected = expected_full_hashes[i];
+    const SBFullHashResult& actual = full_hashes[i];
+    EXPECT_TRUE(SBFullHashEqual(expected.hash, actual.hash));
+    EXPECT_EQ(expected.metadata, actual.metadata);
+    EXPECT_EQ(expected.cache_duration, actual.cache_duration);
+  }
+}
+
+TEST_F(SafeBrowsingProtocolManagerTest, TestGetV4HashErrorHandlingNetwork) {
+  net::TestURLFetcherFactory factory;
+  scoped_ptr<SafeBrowsingProtocolManager> pm(CreateProtocolManager(NULL));
+
+  std::vector<SBPrefix> prefixes;
+  std::vector<SBFullHashResult> expected_full_hashes;
+  base::TimeDelta expected_cache_duration;
+
+  pm->GetFullHashesWithApis(prefixes,
+      base::Bind(&ValidateGetV4HashResults,
+                 expected_full_hashes, expected_cache_duration));
+
+  net::TestURLFetcher* fetcher = factory.GetFetcherByID(0);
+  DCHECK(fetcher);
+  // Failed request status should result in error.
+  fetcher->set_status(net::URLRequestStatus(net::URLRequestStatus::FAILED,
+                                            net::ERR_CONNECTION_RESET));
+  fetcher->set_response_code(200);
+  fetcher->SetResponseString(GetStockV4HashResponse());
+  fetcher->delegate()->OnURLFetchComplete(fetcher);
+
+  // Should have recorded one error, but back off multiplier is unchanged.
+  EXPECT_EQ(1ul, pm->gethash_v4_error_count_);
+  EXPECT_EQ(1ul, pm->gethash_v4_back_off_mult_);
+}
+
+TEST_F(SafeBrowsingProtocolManagerTest,
+    TestGetV4HashErrorHandlingResponseCode) {
+  net::TestURLFetcherFactory factory;
+  scoped_ptr<SafeBrowsingProtocolManager> pm(CreateProtocolManager(NULL));
+
+  std::vector<SBPrefix> prefixes;
+  std::vector<SBFullHashResult> expected_full_hashes;
+  base::TimeDelta expected_cache_duration;
+
+  pm->GetFullHashesWithApis(prefixes,
+      base::Bind(&ValidateGetV4HashResults,
+                 expected_full_hashes, expected_cache_duration));
+
+  net::TestURLFetcher* fetcher = factory.GetFetcherByID(0);
+  DCHECK(fetcher);
+  fetcher->set_status(net::URLRequestStatus());
+  // Response code of anything other than 200 should result in error.
+  fetcher->set_response_code(204);
+  fetcher->SetResponseString(GetStockV4HashResponse());
+  fetcher->delegate()->OnURLFetchComplete(fetcher);
+
+  // Should have recorded one error, but back off multiplier is unchanged.
+  EXPECT_EQ(1ul, pm->gethash_v4_error_count_);
+  EXPECT_EQ(1ul, pm->gethash_v4_back_off_mult_);
+}
+
+TEST_F(SafeBrowsingProtocolManagerTest, TestGetV4HashErrorHandlingOK) {
+  net::TestURLFetcherFactory factory;
+  scoped_ptr<SafeBrowsingProtocolManager> pm(CreateProtocolManager(NULL));
+
+  std::vector<SBPrefix> prefixes;
+  std::vector<SBFullHashResult> expected_full_hashes;
+  SBFullHashResult hash_result;
+  hash_result.hash = SBFullHashForString("Everything's shiny, Cap'n.");
+  hash_result.metadata = "NOTIFICATIONS,";
+  hash_result.cache_duration = base::TimeDelta::FromSeconds(300);
+  expected_full_hashes.push_back(hash_result);
+  base::TimeDelta expected_cache_duration = base::TimeDelta::FromSeconds(600);
+
+  pm->GetFullHashesWithApis(prefixes,
+      base::Bind(&ValidateGetV4HashResults,
+                 expected_full_hashes, expected_cache_duration));
+
+  net::TestURLFetcher* fetcher = factory.GetFetcherByID(0);
+  DCHECK(fetcher);
+  fetcher->set_status(net::URLRequestStatus());
+  fetcher->set_response_code(200);
+  fetcher->SetResponseString(GetStockV4HashResponse());
+  fetcher->delegate()->OnURLFetchComplete(fetcher);
+
+  // No error, back off multiplier is unchanged.
+  EXPECT_EQ(0ul, pm->gethash_v4_error_count_);
+  EXPECT_EQ(1ul, pm->gethash_v4_back_off_mult_);
+}
+
 // Ensure that we respect section 5 of the SafeBrowsing protocol specification.
 TEST_F(SafeBrowsingProtocolManagerTest, TestBackOffTimes) {
   scoped_ptr<SafeBrowsingProtocolManager> pm(CreateProtocolManager(NULL));
diff --git a/chrome/browser/ui/ash/launcher/chrome_launcher_controller.cc b/chrome/browser/ui/ash/launcher/chrome_launcher_controller.cc
index e76928b..f8c9c91 100644
--- a/chrome/browser/ui/ash/launcher/chrome_launcher_controller.cc
+++ b/chrome/browser/ui/ash/launcher/chrome_launcher_controller.cc
@@ -779,11 +779,6 @@
     return;
   }
 
-#if defined(OS_WIN)
-  if (LaunchedInNativeDesktop(app_id))
-    return;
-#endif
-
   // The app will be created for the currently active profile.
   AppLaunchParams params(
       profile_, extension, ui::DispositionFromEventFlags(event_flags),
diff --git a/chrome/browser/ui/ash/launcher/chrome_launcher_controller.h b/chrome/browser/ui/ash/launcher/chrome_launcher_controller.h
index 9315d5ba..e63fa2f 100644
--- a/chrome/browser/ui/ash/launcher/chrome_launcher_controller.h
+++ b/chrome/browser/ui/ash/launcher/chrome_launcher_controller.h
@@ -551,11 +551,6 @@
   // Forget the current profile to allow attaching to a new one.
   void ReleaseProfile();
 
-  // Returns true if |app_id| is a Packaged App that has already launched on the
-  // native desktop and, if so, executes it as a desktop shortcut to activate
-  // desktop mode and send another OnLaunched event to the Extension.
-  bool LaunchedInNativeDesktop(const std::string& app_id);
-
   static ChromeLauncherController* instance_;
 
   ash::ShelfModel* model_;
diff --git a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_chromeos.cc b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_chromeos.cc
deleted file mode 100644
index 1a1f86c..0000000
--- a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_chromeos.cc
+++ /dev/null
@@ -1,10 +0,0 @@
-// Copyright 2013 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/ui/ash/launcher/chrome_launcher_controller.h"
-
-bool ChromeLauncherController::LaunchedInNativeDesktop(
-    const std::string& app_id) {
-  return false;
-}
diff --git a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_win.cc b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_win.cc
deleted file mode 100644
index 29ec4ac1..0000000
--- a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_win.cc
+++ /dev/null
@@ -1,50 +0,0 @@
-// Copyright 2013 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/ui/ash/launcher/chrome_launcher_controller.h"
-
-#include "base/path_service.h"
-#include "base/strings/string16.h"
-#include "base/strings/stringprintf.h"
-#include "base/strings/utf_string_conversions.h"
-#include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/ui/host_desktop.h"
-#include "chrome/common/chrome_switches.h"
-#include "extensions/browser/app_window/app_window.h"
-#include "extensions/browser/app_window/app_window_registry.h"
-#include "extensions/common/constants.h"
-#include "ui/aura/remote_window_tree_host_win.h"
-
-bool ChromeLauncherController::LaunchedInNativeDesktop(
-    const std::string& app_id) {
-  // If an app has any existing windows on the native desktop, funnel the
-  // launch request through the viewer process to desktop Chrome. This allows
-  // Ash to relinquish foreground window status and trigger a switch to
-  // desktop mode.
-  extensions::AppWindow* any_existing_window =
-      extensions::AppWindowRegistry::Get(profile())
-          ->GetCurrentAppWindowForApp(app_id);
-  if (!any_existing_window ||
-      chrome::GetHostDesktopTypeForNativeWindow(
-          any_existing_window->GetNativeWindow())
-      != chrome::HOST_DESKTOP_TYPE_NATIVE) {
-    return false;
-  }
-  base::FilePath exe_path;
-  if (!PathService::Get(base::FILE_EXE, &exe_path)) {
-    NOTREACHED();
-    return false;
-  }
-
-  // Construct parameters for ShellExecuteEx that mimic a desktop shortcut
-  // for the app in the current Profile.
-  std::string spec = base::StringPrintf("\"--%s=%s\" \"--%s=%s\"",
-      switches::kProfileDirectory,
-      profile_->GetPath().BaseName().AsUTF8Unsafe().c_str(),
-      switches::kAppId,
-      app_id.c_str());
-  aura::RemoteWindowTreeHostWin::Instance()->HandleOpenURLOnDesktop(
-      exe_path, base::UTF8ToUTF16(spec));
-  return true;
-}
diff --git a/chrome/browser/ui/views/apps/chrome_native_app_window_views_win.cc b/chrome/browser/ui/views/apps/chrome_native_app_window_views_win.cc
index eebd1f2a..e9aa438 100644
--- a/chrome/browser/ui/views/apps/chrome_native_app_window_views_win.cc
+++ b/chrome/browser/ui/views/apps/chrome_native_app_window_views_win.cc
@@ -24,7 +24,6 @@
 #include "extensions/browser/app_window/app_window.h"
 #include "extensions/browser/app_window/app_window_registry.h"
 #include "extensions/common/extension.h"
-#include "ui/aura/remote_window_tree_host_win.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/win/shell.h"
 #include "ui/views/widget/desktop_aura/desktop_native_widget_aura.h"
diff --git a/chrome/browser/ui/webui/engagement/site_engagement.mojom b/chrome/browser/ui/webui/engagement/site_engagement.mojom
index a6d2042..0d9cc4a 100644
--- a/chrome/browser/ui/webui/engagement/site_engagement.mojom
+++ b/chrome/browser/ui/webui/engagement/site_engagement.mojom
@@ -9,4 +9,5 @@
 
 interface SiteEngagementUIHandler {
   GetSiteEngagementInfo() => (array<SiteEngagementInfo> info);
+  SetSiteEngagementScoreForOrigin(string origin, double score);
 };
diff --git a/chrome/browser/ui/webui/engagement/site_engagement_ui.cc b/chrome/browser/ui/webui/engagement/site_engagement_ui.cc
index 76c34549..a3359b482 100644
--- a/chrome/browser/ui/webui/engagement/site_engagement_ui.cc
+++ b/chrome/browser/ui/webui/engagement/site_engagement_ui.cc
@@ -50,6 +50,18 @@
     callback.Run(std::move(engagement_info));
   }
 
+  void SetSiteEngagementScoreForOrigin(const mojo::String& origin,
+                                       double score) override {
+    GURL origin_gurl(origin);
+    if (!origin_gurl.is_valid() || score < 0 ||
+        score > SiteEngagementScore::kMaxPoints) {
+      return;
+    }
+
+    SiteEngagementService* service = SiteEngagementService::Get(profile_);
+    service->ResetScoreForURL(origin_gurl, score);
+  }
+
  private:
   // The Profile* handed to us in our constructor.
   Profile* profile_;
diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi
index db7c848..cd435cc 100644
--- a/chrome/chrome_browser.gypi
+++ b/chrome/chrome_browser.gypi
@@ -738,6 +738,8 @@
       'browser/android/download/chrome_download_delegate.h',
       'browser/android/download/chrome_download_manager_overwrite_infobar_delegate.cc',
       'browser/android/download/chrome_download_manager_overwrite_infobar_delegate.h',
+      'browser/android/download/download_manager_service.cc',
+      'browser/android/download/download_manager_service.h',
       'browser/android/download/download_overwrite_infobar_delegate.cc',
       'browser/android/download/download_overwrite_infobar_delegate.h',
       'browser/android/download/mock_download_controller_android.cc',
@@ -1354,8 +1356,6 @@
       'browser/usb/web_usb_permission_bubble.h',
     ],
     'chrome_browser_win_sources': [
-      'browser/browser_process_platform_part_aurawin.cc',
-      'browser/browser_process_platform_part_aurawin.h',
       'browser/first_run/try_chrome_dialog_view.cc',
       'browser/first_run/try_chrome_dialog_view.h',
       'browser/first_run/upgrade_util.cc',
@@ -1367,8 +1367,6 @@
       'browser/hang_monitor/hung_plugin_action.h',
       'browser/hang_monitor/hung_window_detector.cc',
       'browser/hang_monitor/hung_window_detector.h',
-      'browser/metro_viewer/chrome_metro_viewer_process_host_aurawin.cc',
-      'browser/metro_viewer/chrome_metro_viewer_process_host_aurawin.h',
       'browser/password_manager/password_manager_util_win.cc',
       'browser/password_manager/password_manager_util_win.h',
     ],
@@ -1841,6 +1839,7 @@
       'android/java/src/org/chromium/chrome/browser/dom_distiller/DomDistillerTabUtils.java',
       'android/java/src/org/chromium/chrome/browser/dom_distiller/DomDistillerUIUtils.java',
       'android/java/src/org/chromium/chrome/browser/download/ChromeDownloadDelegate.java',
+      'android/java/src/org/chromium/chrome/browser/download/DownloadManagerService.java',
       'android/java/src/org/chromium/chrome/browser/favicon/FaviconHelper.java',
       'android/java/src/org/chromium/chrome/browser/favicon/LargeIconBridge.java',
       'android/java/src/org/chromium/chrome/browser/feedback/ConnectivityChecker.java',
@@ -3832,7 +3831,6 @@
             '../ui/metro_viewer/metro_viewer.gyp:metro_viewer_messages',
             '../ui/views/controls/webview/webview.gyp:webview',
             '../ui/views/views.gyp:views',
-            '../win8/win8.gyp:metro_viewer',
           ],
           'export_dependent_settings': [
             '../third_party/kasko/kasko.gyp:kasko',
diff --git a/chrome/chrome_browser_ui.gypi b/chrome/chrome_browser_ui.gypi
index 3abdf0af..70ff6b34 100644
--- a/chrome/chrome_browser_ui.gypi
+++ b/chrome/chrome_browser_ui.gypi
@@ -558,8 +558,6 @@
       'browser/ui/ash/launcher/chrome_launcher_app_menu_item_v2app.h',
       'browser/ui/ash/launcher/chrome_launcher_controller.cc',
       'browser/ui/ash/launcher/chrome_launcher_controller.h',
-      'browser/ui/ash/launcher/chrome_launcher_controller_chromeos.cc',
-      'browser/ui/ash/launcher/chrome_launcher_controller_win.cc',
       'browser/ui/ash/launcher/launcher_app_tab_helper.cc',
       'browser/ui/ash/launcher/launcher_app_tab_helper.h',
       'browser/ui/ash/launcher/launcher_application_menu_item_model.cc',
diff --git a/chrome/chrome_tests_unit.gypi b/chrome/chrome_tests_unit.gypi
index da034204..3cfed39 100644
--- a/chrome/chrome_tests_unit.gypi
+++ b/chrome/chrome_tests_unit.gypi
@@ -18,6 +18,7 @@
       'browser/android/data_usage/data_use_ui_tab_model_unittest.cc',
       'browser/android/data_usage/external_data_use_observer_unittest.cc',
       'browser/android/data_usage/tab_data_use_entry_unittest.cc',
+      'browser/android/download/download_manager_service_unittest.cc',
       'browser/android/history_report/delta_file_backend_leveldb_unittest.cc',
       'browser/android/history_report/delta_file_commons_unittest.cc',
       'browser/android/history_report/usage_reports_buffer_backend_unittest.cc',
diff --git a/chrome/common/localized_error.cc b/chrome/common/localized_error.cc
index c78fbf75..8ff1643 100644
--- a/chrome/common/localized_error.cc
+++ b/chrome/common/localized_error.cc
@@ -17,8 +17,6 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/values.h"
 #include "build/build_config.h"
-#include "chrome/grit/chromium_strings.h"
-#include "chrome/grit/google_chrome_strings.h"
 #include "components/error_page/common/error_page_params.h"
 #include "components/error_page/common/error_page_switches.h"
 #include "components/error_page/common/net_error_info.h"
@@ -625,8 +623,6 @@
 
   summary->SetString("failedUrl", failed_url_string);
   summary->SetString("hostName", host_name);
-  summary->SetString("productName",
-                     l10n_util::GetStringUTF16(IDS_PRODUCT_NAME));
 
   error_strings->SetString(
       "details", l10n_util::GetStringUTF16(IDS_ERRORPAGE_NET_BUTTON_DETAILS));
diff --git a/chrome/test/kasko/py/kasko/report.py b/chrome/test/kasko/py/kasko/report.py
index 6e0c350..8eb884eb4 100755
--- a/chrome/test/kasko/py/kasko/report.py
+++ b/chrome/test/kasko/py/kasko/report.py
@@ -20,10 +20,20 @@
 
 
 def ValidateCrashReport(report, expectations=None):
-  # Generate default expectations, and merge in any additional ones.
-  expected_keys = {'guid': 'GetCrashKeysForKasko',
-                   'kasko-generated-by-version': 'Kasko',
-                   'kasko-uploaded-by-version': 'Kasko'}
+  expected_keys = {}
+
+  # The following keys are all expected to be set in all crashes, and should
+  # be set by GetCrashKeysForKasko.
+  get_crash_keys = 'GetCrashKeysForKasko'
+  for k in ['guid', 'prod', 'plat', 'ver', 'ptype', 'channel']:
+    expected_keys[k] = get_crash_keys
+
+  # The following crash keys are expected to be set by the Kasko code itself.
+  kasko = 'Kasko'
+  for k in ['kasko-generated-by-version', 'kasko-uploaded-by-version']:
+    expected_keys[k] = kasko
+
+  # Merge in additional expectations.
   if expectations:
     for key, value in expectations.iteritems():
       expected_keys[key] = value
diff --git a/chromeos/CHROMEOS_LKGM b/chromeos/CHROMEOS_LKGM
index 186115a..22cc9488 100644
--- a/chromeos/CHROMEOS_LKGM
+++ b/chromeos/CHROMEOS_LKGM
@@ -1 +1 @@
-7830.0.0
\ No newline at end of file
+7842.0.0
\ No newline at end of file
diff --git a/components/crash/content/app/crashpad.cc b/components/crash/content/app/crashpad.cc
index dfe83cac..78216d2 100644
--- a/components/crash/content/app/crashpad.cc
+++ b/components/crash/content/app/crashpad.cc
@@ -246,9 +246,14 @@
 #if BUILDFLAG(ENABLE_KASKO)
 
 void GetCrashKeysForKasko(std::vector<kasko::api::CrashKey>* crash_keys) {
-  // Reserve room for an extra key, the guid.
+  // Get the platform annotations.
+  std::map<std::string, std::string> annotations;
+  internal::GetPlatformCrashpadAnnotations(&annotations);
+
+  // Reserve room for the GUID and the platform annotations.
   crash_keys->clear();
-  crash_keys->reserve(g_simple_string_dictionary->GetCount() + 1);
+  crash_keys->reserve(
+      g_simple_string_dictionary->GetCount() + 1 + annotations.size());
 
   // Set the Crashpad client ID in the crash keys.
   bool got_guid = false;
@@ -275,11 +280,25 @@
     if (got_guid && ::strncmp(entry->key, kGuid, arraysize(kGuid)) == 0)
       continue;
 
+    // Skip any platform annotations as they'll be set below.
+    if (annotations.count(entry->key))
+      continue;
+
     kasko::api::CrashKey kv;
     wcsncpy_s(kv.name, base::UTF8ToWide(entry->key).c_str(), _TRUNCATE);
     wcsncpy_s(kv.value, base::UTF8ToWide(entry->value).c_str(), _TRUNCATE);
     crash_keys->push_back(kv);
   }
+
+  // Merge in the platform annotations.
+  for (const auto& entry : annotations) {
+    kasko::api::CrashKey kv;
+    wcsncpy_s(kv.name, base::UTF8ToWide(entry.first).c_str(),
+              _TRUNCATE);
+    wcsncpy_s(kv.value, base::UTF8ToWide(entry.second).c_str(),
+              _TRUNCATE);
+    crash_keys->push_back(kv);
+  }
 }
 
 #endif  // BUILDFLAG(ENABLE_KASKO)
diff --git a/components/crash/content/app/crashpad.h b/components/crash/content/app/crashpad.h
index 1f9f007..a3f5e6c4 100644
--- a/components/crash/content/app/crashpad.h
+++ b/components/crash/content/app/crashpad.h
@@ -7,6 +7,7 @@
 
 #include <time.h>
 
+#include <map>
 #include <string>
 #include <vector>
 
@@ -82,6 +83,13 @@
 
 namespace internal {
 
+#if defined(OS_WIN)
+// Returns platform specific annotations. This is broken out on Windows only so
+// that it may be reused by GetCrashKeysForKasko.
+void GetPlatformCrashpadAnnotations(
+    std::map<std::string, std::string>* annotations);
+#endif  // defined(OS_WIN)
+
 // The platform-specific portion of InitializeCrashpad().
 // Returns the database path, if initializing in the browser process.
 base::FilePath PlatformCrashpadInitialization(bool initial_client,
diff --git a/components/crash/content/app/crashpad_win.cc b/components/crash/content/app/crashpad_win.cc
index 1c241ca..1628ab6 100644
--- a/components/crash/content/app/crashpad_win.cc
+++ b/components/crash/content/app/crashpad_win.cc
@@ -30,6 +30,26 @@
 
 }  // namespace
 
+void GetPlatformCrashpadAnnotations(
+    std::map<std::string, std::string>* annotations) {
+  CrashReporterClient* crash_reporter_client = GetCrashReporterClient();
+  base::FilePath exe_file;
+  CHECK(PathService::Get(base::FILE_EXE, &exe_file));
+  base::string16 product_name, version, special_build, channel_name;
+  crash_reporter_client->GetProductNameAndVersion(
+      exe_file, &product_name, &version, &special_build, &channel_name);
+  (*annotations)["prod"] = base::UTF16ToUTF8(product_name);
+  (*annotations)["ver"] = base::UTF16ToUTF8(version);
+  (*annotations)["channel"] = base::UTF16ToUTF8(channel_name);
+  if (!special_build.empty())
+    (*annotations)["special"] = base::UTF16ToUTF8(special_build);
+#if defined(ARCH_CPU_X86)
+  (*annotations)["plat"] = std::string("Win32");
+#elif defined(ARCH_CPU_X86_64)
+  (*annotations)["plat"] = std::string("Win64");
+#endif
+}
+
 base::FilePath PlatformCrashpadInitialization(bool initial_client,
                                               bool browser_process) {
   base::FilePath database_path;  // Only valid in the browser process.
@@ -44,22 +64,9 @@
     CrashReporterClient* crash_reporter_client = GetCrashReporterClient();
     crash_reporter_client->GetCrashDumpLocation(&database_path);
 
-    base::FilePath exe_file;
-    CHECK(PathService::Get(base::FILE_EXE, &exe_file));
-    base::string16 product_name, version, special_build, channel_name;
-    crash_reporter_client->GetProductNameAndVersion(
-        exe_file, &product_name, &version, &special_build, &channel_name);
     std::map<std::string, std::string> process_annotations;
-    process_annotations["prod"] = base::UTF16ToUTF8(product_name);
-    process_annotations["ver"] = base::UTF16ToUTF8(version);
-    process_annotations["channel"] = base::UTF16ToUTF8(channel_name);
-    if (!special_build.empty())
-      process_annotations["special"] = base::UTF16ToUTF8(special_build);
-#if defined(ARCH_CPU_X86)
-    process_annotations["plat"] = std::string("Win32");
-#elif defined(ARCH_CPU_X86_64)
-    process_annotations["plat"] = std::string("Win64");
-#endif
+    GetPlatformCrashpadAnnotations(&process_annotations);
+
 #if defined(GOOGLE_CHROME_BUILD)
     std::string url = "https://clients2.google.com/cr/report";
 #else
@@ -70,6 +77,8 @@
 
     // In test binaries, use crashpad_handler directly. Otherwise, we launch
     // chrome.exe with --type=crashpad-handler.
+    base::FilePath exe_file;
+    CHECK(PathService::Get(base::FILE_EXE, &exe_file));
     if (exe_file.BaseName().value() != FILE_PATH_LITERAL("chrome.exe")) {
       base::FilePath exe_dir = exe_file.DirName();
       exe_file = exe_dir.Append(FILE_PATH_LITERAL("crashpad_handler.exe"));
diff --git a/components/html_viewer/blink_platform_impl.cc b/components/html_viewer/blink_platform_impl.cc
index c3d5d1a..714f16f 100644
--- a/components/html_viewer/blink_platform_impl.cc
+++ b/components/html_viewer/blink_platform_impl.cc
@@ -153,12 +153,6 @@
   return &scrollbar_behavior_;
 }
 
-const unsigned char* BlinkPlatformImpl::getTraceCategoryEnabledFlag(
-    const char* category_name) {
-  static const unsigned char buf[] = "*";
-  return buf;
-}
-
 blink::WebGraphicsContext3D*
 BlinkPlatformImpl::createOffscreenGraphicsContext3D(
     const blink::WebGraphicsContext3D::Attributes& attributes,
diff --git a/components/html_viewer/blink_platform_impl.h b/components/html_viewer/blink_platform_impl.h
index df74298..0494d1c 100644
--- a/components/html_viewer/blink_platform_impl.h
+++ b/components/html_viewer/blink_platform_impl.h
@@ -77,8 +77,6 @@
   blink::WebWaitableEvent* waitMultipleEvents(
       const blink::WebVector<blink::WebWaitableEvent*>& events) override;
   blink::WebScrollbarBehavior* scrollbarBehavior() override;
-  const unsigned char* getTraceCategoryEnabledFlag(
-      const char* category_name) override;
   blink::WebGraphicsContext3D* createOffscreenGraphicsContext3D(
       const blink::WebGraphicsContext3D::Attributes& attributes,
       blink::WebGraphicsContext3D* share_context) override;
diff --git a/components/password_manager/sync/browser/sync_credentials_filter.cc b/components/password_manager/sync/browser/sync_credentials_filter.cc
index 93031c7..7e9699d 100644
--- a/components/password_manager/sync/browser/sync_credentials_filter.cc
+++ b/components/password_manager/sync/browser/sync_credentials_filter.cc
@@ -64,9 +64,6 @@
       std::partition(results.begin(), results.end(),
                      [this](PasswordForm* form) { return ShouldSave(*form); });
 
-  // TODO(vabr): Improve the description of the histogram to mention that it is
-  // only reported for forms where the sync credentials would have been filled
-  // in.
   UMA_HISTOGRAM_BOOLEAN("PasswordManager.SyncCredentialFiltered",
                         begin_of_removed != results.end());
 
diff --git a/components/scheduler/renderer/renderer_scheduler_impl.cc b/components/scheduler/renderer/renderer_scheduler_impl.cc
index d739302..33e7b8d 100644
--- a/components/scheduler/renderer/renderer_scheduler_impl.cc
+++ b/components/scheduler/renderer/renderer_scheduler_impl.cc
@@ -682,17 +682,10 @@
 
     case UseCase::MAIN_THREAD_GESTURE:
       // In main thread gestures we don't have perfect knowledge about which
-      // things we should be prioritizing. The following is best guess
-      // heuristic which lets us produce frames quickly but does not prevent
-      // loading of additional content.
+      // things we should be prioritizing, so we don't attempt to block
+      // expensive tasks because we don't know whether they were integral to the
+      // page's functionality or not.
       new_policy.compositor_queue_priority = TaskQueue::HIGH_PRIORITY;
-      if (touchstart_expected_soon) {
-        block_expensive_loading_tasks = true;
-        block_expensive_timer_tasks = true;
-      } else {
-        block_expensive_loading_tasks = false;
-        block_expensive_timer_tasks = true;
-      }
       break;
 
     case UseCase::TOUCHSTART:
@@ -705,7 +698,10 @@
       break;
 
     case UseCase::NONE:
-      if (touchstart_expected_soon) {
+      // It's only safe to block tasks that are (likely to be) compositor
+      // driven.
+      if (touchstart_expected_soon &&
+          AnyThread().last_gesture_was_compositor_driven) {
         block_expensive_loading_tasks = true;
         block_expensive_timer_tasks = true;
       }
@@ -852,7 +848,6 @@
 
   // TODO(alexclarke): return UseCase::LOADING if signals suggest the system is
   // in the initial 1s of RAIL loading.
-
   return UseCase::NONE;
 }
 
diff --git a/components/scheduler/renderer/renderer_scheduler_impl_unittest.cc b/components/scheduler/renderer/renderer_scheduler_impl_unittest.cc
index 87d5cc3..1e84f1a 100644
--- a/components/scheduler/renderer/renderer_scheduler_impl_unittest.cc
+++ b/components/scheduler/renderer/renderer_scheduler_impl_unittest.cc
@@ -315,19 +315,37 @@
     // TODO(alexclarke): Revisit this.
     scheduler_->DidHandleInputEventOnCompositorThread(
         FakeInputEvent(blink::WebInputEvent::TouchStart),
-        RendererScheduler::InputEventState::EVENT_CONSUMED_BY_COMPOSITOR);
+        RendererScheduler::InputEventState::EVENT_FORWARDED_TO_MAIN_THREAD);
+    scheduler_->DidHandleInputEventOnMainThread(
+        FakeInputEvent(blink::WebInputEvent::TouchStart));
     scheduler_->DidHandleInputEventOnCompositorThread(
         FakeInputEvent(blink::WebInputEvent::TouchMove),
-        RendererScheduler::InputEventState::EVENT_CONSUMED_BY_COMPOSITOR);
+        RendererScheduler::InputEventState::EVENT_FORWARDED_TO_MAIN_THREAD);
     scheduler_->DidHandleInputEventOnCompositorThread(
         FakeInputEvent(blink::WebInputEvent::TouchMove),
+        RendererScheduler::InputEventState::EVENT_FORWARDED_TO_MAIN_THREAD);
+    scheduler_->DidHandleInputEventOnCompositorThread(
+        FakeInputEvent(blink::WebInputEvent::GestureScrollBegin),
+        RendererScheduler::InputEventState::EVENT_CONSUMED_BY_COMPOSITOR);
+    scheduler_->DidHandleInputEventOnCompositorThread(
+        FakeInputEvent(blink::WebInputEvent::GestureScrollUpdate),
+        RendererScheduler::InputEventState::EVENT_CONSUMED_BY_COMPOSITOR);
+    scheduler_->DidHandleInputEventOnMainThread(
+        FakeInputEvent(blink::WebInputEvent::TouchMove));
+    scheduler_->DidHandleInputEventOnMainThread(
+        FakeInputEvent(blink::WebInputEvent::TouchMove));
+    scheduler_->DidHandleInputEventOnCompositorThread(
+        FakeInputEvent(blink::WebInputEvent::GestureScrollEnd),
         RendererScheduler::InputEventState::EVENT_CONSUMED_BY_COMPOSITOR);
     scheduler_->DidHandleInputEventOnCompositorThread(
         FakeInputEvent(blink::WebInputEvent::TouchEnd),
-        RendererScheduler::InputEventState::EVENT_CONSUMED_BY_COMPOSITOR);
+        RendererScheduler::InputEventState::EVENT_FORWARDED_TO_MAIN_THREAD);
+    scheduler_->DidHandleInputEventOnMainThread(
+        FakeInputEvent(blink::WebInputEvent::TouchEnd));
     scheduler_->ForceUpdatePolicy();
     clock_->Advance(base::TimeDelta::FromSeconds(60));
     scheduler_->ForceUpdatePolicy();
+    EXPECT_EQ(RendererScheduler::UseCase::NONE, CurrentUseCase());
   }
 
   void SimulateExpensiveTasks(
@@ -952,8 +970,7 @@
               testing::ElementsAre(std::string("C1"), std::string("T1")));
 }
 
-TEST_F(RendererSchedulerImplTest,
-       ExpensiveTimersDontRunWhenMainThreadScrolling) {
+TEST_F(RendererSchedulerImplTest, ExpensiveTimersDoRunWhenMainThreadScrolling) {
   std::vector<std::string> run_order;
 
   scheduler_->SetHasVisibleRenderWidgetWithTouchHandler(true);
@@ -962,32 +979,18 @@
   SimulateMainThreadGestureStart(TouchEventPolicy::SEND_TOUCH_START,
                                  blink::WebInputEvent::GestureScrollBegin);
 
-  // Timers should now be disabled during main thread user user interactions.
   PostTestTasks(&run_order, "C1 T1");
 
   RunUntilIdle();
   EXPECT_FALSE(TouchStartExpectedSoon());
   EXPECT_EQ(RendererScheduler::UseCase::MAIN_THREAD_GESTURE, CurrentUseCase());
 
-  EXPECT_THAT(run_order, testing::ElementsAre(std::string("C1")));
-
-  scheduler_->DidHandleInputEventOnCompositorThread(
-      FakeInputEvent(blink::WebInputEvent::GestureScrollEnd),
-      RendererScheduler::InputEventState::EVENT_FORWARDED_TO_MAIN_THREAD);
-  scheduler_->DidHandleInputEventOnMainThread(
-      FakeInputEvent(blink::WebInputEvent::GestureScrollEnd));
-
-  clock_->Advance(subsequent_input_expected_after_input_duration() * 2);
-
-  run_order.clear();
-  RunUntilIdle();
-  EXPECT_FALSE(TouchStartExpectedSoon());
-  EXPECT_EQ(RendererScheduler::UseCase::NONE, CurrentUseCase());
-  EXPECT_THAT(run_order, testing::ElementsAre(std::string("T1")));
+  EXPECT_THAT(run_order,
+              testing::ElementsAre(std::string("C1"), std::string("T1")));
 }
 
 TEST_F(RendererSchedulerImplTest,
-       ExpensiveTimersDontRunWhenMainThreadScrolling_AndOnCriticalPath) {
+       ExpensiveTimersDoRunWhenMainThreadScrolling_AndOnCriticalPath) {
   std::vector<std::string> run_order;
 
   scheduler_->SetHasVisibleRenderWidgetWithTouchHandler(true);
@@ -996,28 +999,14 @@
   SimulateMainThreadGestureStart(TouchEventPolicy::SEND_TOUCH_START,
                                  blink::WebInputEvent::GestureScrollBegin);
 
-  // Timers should now be disabled during main thread user user interactions.
   PostTestTasks(&run_order, "C1 T1");
 
   RunUntilIdle();
   EXPECT_FALSE(TouchStartExpectedSoon());
   EXPECT_EQ(RendererScheduler::UseCase::MAIN_THREAD_GESTURE, CurrentUseCase());
 
-  EXPECT_THAT(run_order, testing::ElementsAre(std::string("C1")));
-
-  scheduler_->DidHandleInputEventOnCompositorThread(
-      FakeInputEvent(blink::WebInputEvent::GestureScrollEnd),
-      RendererScheduler::InputEventState::EVENT_FORWARDED_TO_MAIN_THREAD);
-  scheduler_->DidHandleInputEventOnMainThread(
-      FakeInputEvent(blink::WebInputEvent::GestureScrollEnd));
-
-  clock_->Advance(subsequent_input_expected_after_input_duration() * 2);
-
-  run_order.clear();
-  RunUntilIdle();
-  EXPECT_FALSE(TouchStartExpectedSoon());
-  EXPECT_EQ(RendererScheduler::UseCase::NONE, CurrentUseCase());
-  EXPECT_THAT(run_order, testing::ElementsAre(std::string("T1")));
+  EXPECT_THAT(run_order,
+              testing::ElementsAre(std::string("C1"), std::string("T1")));
 }
 
 TEST_F(RendererSchedulerImplTest, TestTouchstartPolicy_Compositor) {
@@ -2219,7 +2208,8 @@
               testing::ElementsAre(std::string("L1"), std::string("D1")));
 }
 
-TEST_F(RendererSchedulerImplTest, ExpensiveTimerTaskBlocked) {
+TEST_F(RendererSchedulerImplTest,
+       ExpensiveTimerTaskBlocked_UseCase_NONE_PreviousCompositorGesture) {
   std::vector<std::string> run_order;
 
   EnableTaskBlocking();
@@ -2228,14 +2218,68 @@
   SimulateExpensiveTasks(timer_task_runner_);
   ForceTouchStartToBeExpectedSoon();
 
-  scheduler_->DidHandleInputEventOnCompositorThread(
-      FakeInputEvent(blink::WebInputEvent::GestureFlingStart),
-      RendererScheduler::InputEventState::EVENT_FORWARDED_TO_MAIN_THREAD);
   PostTestTasks(&run_order, "T1 D1");
   RunUntilIdle();
 
+  EXPECT_EQ(UseCase::NONE, ForceUpdatePolicyAndGetCurrentUseCase());
+  EXPECT_TRUE(HaveSeenABeginMainframe());
+  EXPECT_FALSE(LoadingTasksSeemExpensive());
+  EXPECT_TRUE(TimerTasksSeemExpensive());
+  EXPECT_TRUE(TouchStartExpectedSoon());
+  EXPECT_THAT(run_order, testing::ElementsAre(std::string("D1")));
+}
+
+TEST_F(RendererSchedulerImplTest,
+       ExpensiveTimerTaskNotBlocked_UseCase_NONE_PreviousMainThreadGesture) {
+  std::vector<std::string> run_order;
+
+  EnableTaskBlocking();
+  scheduler_->SetHasVisibleRenderWidgetWithTouchHandler(true);
+  DoMainFrame();
+  SimulateExpensiveTasks(timer_task_runner_);
+
+  SimulateMainThreadGestureStart(TouchEventPolicy::SEND_TOUCH_START,
+                                 blink::WebInputEvent::GestureScrollBegin);
   EXPECT_EQ(UseCase::MAIN_THREAD_GESTURE,
             ForceUpdatePolicyAndGetCurrentUseCase());
+
+  scheduler_->DidHandleInputEventOnCompositorThread(
+      FakeInputEvent(blink::WebInputEvent::TouchEnd),
+      RendererScheduler::InputEventState::EVENT_FORWARDED_TO_MAIN_THREAD);
+  scheduler_->DidHandleInputEventOnMainThread(
+      FakeInputEvent(blink::WebInputEvent::TouchEnd));
+
+  clock_->Advance(priority_escalation_after_input_duration() * 2);
+  EXPECT_EQ(UseCase::NONE, ForceUpdatePolicyAndGetCurrentUseCase());
+
+  PostTestTasks(&run_order, "T1 D1");
+  RunUntilIdle();
+
+  EXPECT_EQ(UseCase::NONE, ForceUpdatePolicyAndGetCurrentUseCase());
+  EXPECT_TRUE(HaveSeenABeginMainframe());
+  EXPECT_FALSE(LoadingTasksSeemExpensive());
+  EXPECT_TRUE(TimerTasksSeemExpensive());
+  EXPECT_TRUE(TouchStartExpectedSoon());
+  EXPECT_THAT(run_order,
+              testing::ElementsAre(std::string("T1"), std::string("D1")));
+}
+
+TEST_F(RendererSchedulerImplTest,
+       ExpensiveTimerTaskBlocked_UseCase_COMPOSITOR_GESTURE) {
+  std::vector<std::string> run_order;
+
+  EnableTaskBlocking();
+  scheduler_->SetHasVisibleRenderWidgetWithTouchHandler(true);
+  DoMainFrame();
+  SimulateExpensiveTasks(timer_task_runner_);
+  ForceTouchStartToBeExpectedSoon();
+  scheduler_->DidAnimateForInputOnCompositorThread();
+
+  PostTestTasks(&run_order, "T1 D1");
+  RunUntilIdle();
+
+  EXPECT_EQ(UseCase::COMPOSITOR_GESTURE,
+            ForceUpdatePolicyAndGetCurrentUseCase());
   EXPECT_TRUE(HaveSeenABeginMainframe());
   EXPECT_FALSE(LoadingTasksSeemExpensive());
   EXPECT_TRUE(TimerTasksSeemExpensive());
@@ -2243,7 +2287,8 @@
   EXPECT_THAT(run_order, testing::ElementsAre(std::string("D1")));
 }
 
-TEST_F(RendererSchedulerImplTest, ExpensiveTimerTaskNotBlockedIfDisallowed) {
+TEST_F(RendererSchedulerImplTest,
+       ExpensiveTimerTaskNotBlockedIfDissalowed_UseCase_COMPOSITOR_GESTURE) {
   std::vector<std::string> run_order;
 
   EnableTaskBlocking();
@@ -2252,14 +2297,12 @@
   DoMainFrame();
   SimulateExpensiveTasks(timer_task_runner_);
   ForceTouchStartToBeExpectedSoon();
+  scheduler_->DidAnimateForInputOnCompositorThread();
 
-  scheduler_->DidHandleInputEventOnCompositorThread(
-      FakeInputEvent(blink::WebInputEvent::GestureFlingStart),
-      RendererScheduler::InputEventState::EVENT_FORWARDED_TO_MAIN_THREAD);
   PostTestTasks(&run_order, "T1 D1");
   RunUntilIdle();
 
-  EXPECT_EQ(UseCase::MAIN_THREAD_GESTURE,
+  EXPECT_EQ(UseCase::COMPOSITOR_GESTURE,
             ForceUpdatePolicyAndGetCurrentUseCase());
   EXPECT_TRUE(HaveSeenABeginMainframe());
   EXPECT_FALSE(LoadingTasksSeemExpensive());
@@ -2270,7 +2313,7 @@
 }
 
 TEST_F(RendererSchedulerImplTest,
-       ExpensiveTimerTaskBlockedIfTouchStartNotSeen) {
+       ExpensiveTimerTaskNotBlockedIfTouchStartNotSeen) {
   std::vector<std::string> run_order;
 
   scheduler_->SetHasVisibleRenderWidgetWithTouchHandler(true);
@@ -2278,14 +2321,10 @@
   SimulateExpensiveTasks(timer_task_runner_);
   ForceTouchStartToBeExpectedSoon();
 
-  scheduler_->DidHandleInputEventOnCompositorThread(
-      FakeInputEvent(blink::WebInputEvent::GestureFlingStart),
-      RendererScheduler::InputEventState::EVENT_FORWARDED_TO_MAIN_THREAD);
   PostTestTasks(&run_order, "T1 D1");
   RunUntilIdle();
 
-  EXPECT_EQ(UseCase::MAIN_THREAD_GESTURE,
-            ForceUpdatePolicyAndGetCurrentUseCase());
+  EXPECT_EQ(UseCase::NONE, ForceUpdatePolicyAndGetCurrentUseCase());
   EXPECT_TRUE(HaveSeenABeginMainframe());
   EXPECT_FALSE(LoadingTasksSeemExpensive());
   EXPECT_TRUE(TimerTasksSeemExpensive());
@@ -2305,14 +2344,10 @@
   ForceTouchStartToBeExpectedSoon();
   scheduler_->BeginFrameNotExpectedSoon();
 
-  scheduler_->DidHandleInputEventOnCompositorThread(
-      FakeInputEvent(blink::WebInputEvent::GestureFlingStart),
-      RendererScheduler::InputEventState::EVENT_FORWARDED_TO_MAIN_THREAD);
   PostTestTasks(&run_order, "T1 D1");
   RunUntilIdle();
 
-  EXPECT_EQ(UseCase::MAIN_THREAD_GESTURE,
-            ForceUpdatePolicyAndGetCurrentUseCase());
+  EXPECT_EQ(UseCase::NONE, ForceUpdatePolicyAndGetCurrentUseCase());
   EXPECT_TRUE(HaveSeenABeginMainframe());
   EXPECT_FALSE(LoadingTasksSeemExpensive());
   EXPECT_FALSE(TimerTasksSeemExpensive());
@@ -2422,12 +2457,11 @@
   EnableTaskBlocking();
   SimulateExpensiveTasks(loading_task_runner_);
 
-  // Loading tasks should not be disabled during main thread user user
-  // interactions.
+  // Loading tasks should not be disabled during main thread user interactions.
   PostTestTasks(&run_order, "C1 L1");
 
   // Trigger main_thread_gesture UseCase
-  SimulateMainThreadGestureStart(TouchEventPolicy::DONT_SEND_TOUCH_START,
+  SimulateMainThreadGestureStart(TouchEventPolicy::SEND_TOUCH_START,
                                  blink::WebInputEvent::GestureScrollBegin);
   RunUntilIdle();
   EXPECT_EQ(RendererScheduler::UseCase::MAIN_THREAD_GESTURE, CurrentUseCase());
@@ -2516,7 +2550,8 @@
   }
 }
 
-TEST_F(RendererSchedulerImplTest, ExpensiveTimer_Blocked) {
+TEST_F(RendererSchedulerImplTest,
+       ExpensiveTimer_NotBlocked_UseCase_MAIN_THREAD_GESTURE) {
   EnableTaskBlocking();
   scheduler_->SetHasVisibleRenderWidgetWithTouchHandler(true);
   SimulateMainThreadGestureStart(TouchEventPolicy::SEND_TOUCH_START,
@@ -2547,11 +2582,10 @@
     EXPECT_FALSE(LoadingTasksSeemExpensive()) << " i = " << i;
     if (i == 0) {
       EXPECT_FALSE(TimerTasksSeemExpensive()) << " i = " << i;
-      EXPECT_TRUE(simulate_timer_task_ran_) << " i = " << i;
     } else {
       EXPECT_TRUE(TimerTasksSeemExpensive()) << " i = " << i;
-      EXPECT_FALSE(simulate_timer_task_ran_) << " i = " << i;
     }
+    EXPECT_TRUE(simulate_timer_task_ran_) << " i = " << i;
 
     base::TimeDelta time_till_next_frame =
         EstimatedNextFrameBegin() - clock_->NowTicks();
diff --git a/components/test_runner/event_sender.cc b/components/test_runner/event_sender.cc
index a5fcc7b..fdcc7f35 100644
--- a/components/test_runner/event_sender.cc
+++ b/components/test_runner/event_sender.cc
@@ -408,6 +408,30 @@
 #endif
 }
 
+bool GetScrollUnits(gin::Arguments* args, WebGestureEvent::ScrollUnits* units) {
+  std::string units_string;
+  if (!args->PeekNext().IsEmpty()) {
+    if (args->PeekNext()->IsString())
+      args->GetNext(&units_string);
+    if (units_string == "Page") {
+      *units = WebGestureEvent::Page;
+      return true;
+    } else if (units_string == "Pixels") {
+      *units = WebGestureEvent::Pixels;
+      return true;
+    } else if (units_string == "PrecisePixels") {
+      *units = WebGestureEvent::PrecisePixels;
+      return true;
+    } else {
+      args->ThrowError();
+      return false;
+    }
+  } else {
+    *units = WebGestureEvent::PrecisePixels;
+    return true;
+  }
+}
+
 const char* kSourceDeviceStringTouchpad = "touchpad";
 const char* kSourceDeviceStringTouchscreen = "touchscreen";
 
@@ -2142,6 +2166,8 @@
           return;
         }
       }
+      if (!GetScrollUnits(args, &event.data.scrollUpdate.deltaUnits))
+        return;
 
       event.data.scrollUpdate.deltaX = static_cast<float>(x);
       event.data.scrollUpdate.deltaY = static_cast<float>(y);
diff --git a/components/web_view/web_view_impl.cc b/components/web_view/web_view_impl.cc
index 6d140cb72..e07f3cf5 100644
--- a/components/web_view/web_view_impl.cc
+++ b/components/web_view/web_view_impl.cc
@@ -9,7 +9,6 @@
 
 #include "base/bind.h"
 #include "base/command_line.h"
-#include "components/devtools_service/public/cpp/switches.h"
 #include "components/mus/public/cpp/scoped_window_ptr.h"
 #include "components/mus/public/cpp/window.h"
 #include "components/mus/public/cpp/window_tree_connection.h"
@@ -26,14 +25,6 @@
 #include "url/gurl.h"
 
 namespace web_view {
-namespace {
-
-bool EnableRemoteDebugging() {
-  return base::CommandLine::ForCurrentProcess()->HasSwitch(
-      devtools_service::kRemoteDebuggingPort);
-}
-
-}  // namespace
 
 using web_view::mojom::ButtonState;
 
@@ -50,8 +41,7 @@
       content_(nullptr),
       find_controller_(this),
       navigation_controller_(this) {
-  if (EnableRemoteDebugging())
-    devtools_agent_.reset(new FrameDevToolsAgent(app_, this));
+  devtools_agent_.reset(new FrameDevToolsAgent(app_, this));
   OnDidNavigate();
 }
 
diff --git a/content/browser/android/download_controller_android_impl.cc b/content/browser/android/download_controller_android_impl.cc
index feb8de3..a314d08a 100644
--- a/content/browser/android/download_controller_android_impl.cc
+++ b/content/browser/android/download_controller_android_impl.cc
@@ -451,7 +451,9 @@
           base::android::GetApplicationContext(), jurl.obj(), jmime_type.obj(),
           jfilename.obj(), jpath.obj(), item->GetReceivedBytes(), true,
           item->GetId(), item->PercentComplete(), time_delta.InMilliseconds(),
-          item->HasUserGesture());
+          item->HasUserGesture(),
+          // Get all requirements that allows a download to be resumable.
+          !item->GetBrowserContext()->IsOffTheRecord());
       break;
     }
     case DownloadItem::COMPLETE:
diff --git a/content/browser/android/download_controller_android_impl.h b/content/browser/android/download_controller_android_impl.h
index 36c108e3..386135e 100644
--- a/content/browser/android/download_controller_android_impl.h
+++ b/content/browser/android/download_controller_android_impl.h
@@ -30,7 +30,6 @@
 #include "base/memory/scoped_vector.h"
 #include "base/memory/singleton.h"
 #include "content/public/browser/android/download_controller_android.h"
-#include "content/public/browser/download_item.h"
 #include "net/cookies/cookie_monster.h"
 #include "url/gurl.h"
 
@@ -44,8 +43,7 @@
 class RenderViewHost;
 class WebContents;
 
-class DownloadControllerAndroidImpl : public DownloadControllerAndroid,
-                                      public DownloadItem::Observer {
+class DownloadControllerAndroidImpl : public DownloadControllerAndroid {
  public:
   static DownloadControllerAndroidImpl* GetInstance();
 
diff --git a/content/browser/background_sync/background_sync_browsertest.cc b/content/browser/background_sync/background_sync_browsertest.cc
index a5de6ad..60d517e 100644
--- a/content/browser/background_sync/background_sync_browsertest.cc
+++ b/content/browser/background_sync/background_sync_browsertest.cc
@@ -621,7 +621,8 @@
   EXPECT_FALSE(GetRegistrationOneShot("delay"));
 }
 
-IN_PROC_BROWSER_TEST_F(BackgroundSyncBrowserTest, VerifyRetry) {
+// Disabled due to flakiness. See https://crbug.com/578952.
+IN_PROC_BROWSER_TEST_F(BackgroundSyncBrowserTest, DISABLED_VerifyRetry) {
   EXPECT_TRUE(RegisterServiceWorker());
   EXPECT_TRUE(LoadTestPage(kDefaultTestURL));  // Control the page.
 
diff --git a/content/browser/loader/resource_dispatcher_host_impl.cc b/content/browser/loader/resource_dispatcher_host_impl.cc
index 022f410c..d4a6661 100644
--- a/content/browser/loader/resource_dispatcher_host_impl.cc
+++ b/content/browser/loader/resource_dispatcher_host_impl.cc
@@ -563,14 +563,15 @@
   // the requests to cancel first, and then we start cancelling. We assert at
   // the end that there are no more to cancel since the context is about to go
   // away.
-  typedef std::vector<linked_ptr<ResourceLoader>> LoaderList;
+  typedef std::vector<scoped_ptr<ResourceLoader>> LoaderList;
   LoaderList loaders_to_cancel;
 
   for (LoaderMap::iterator i = pending_loaders_.begin();
        i != pending_loaders_.end();) {
-    if (i->second->GetRequestInfo()->GetContext() == context) {
-      loaders_to_cancel.push_back(i->second);
-      IncrementOutstandingRequestsMemory(-1, *i->second->GetRequestInfo());
+    ResourceLoader* loader = i->second.get();
+    if (loader->GetRequestInfo()->GetContext() == context) {
+      loaders_to_cancel.push_back(std::move(i->second));
+      IncrementOutstandingRequestsMemory(-1, *loader->GetRequestInfo());
       pending_loaders_.erase(i++);
     } else {
       ++i;
@@ -579,7 +580,7 @@
 
   for (BlockedLoadersMap::iterator i = blocked_loaders_map_.begin();
        i != blocked_loaders_map_.end();) {
-    BlockedLoadersList* loaders = i->second;
+    BlockedLoadersList* loaders = i->second.get();
     if (loaders->empty()) {
       // This can happen if BlockRequestsForRoute() has been called for a route,
       // but we haven't blocked any matching requests yet.
@@ -588,38 +589,35 @@
     }
     ResourceRequestInfoImpl* info = loaders->front()->GetRequestInfo();
     if (info->GetContext() == context) {
+      scoped_ptr<BlockedLoadersList> deleter(std::move(i->second));
       blocked_loaders_map_.erase(i++);
-      for (BlockedLoadersList::const_iterator it = loaders->begin();
-           it != loaders->end(); ++it) {
-        linked_ptr<ResourceLoader> loader = *it;
+      for (auto& loader : *loaders) {
         info = loader->GetRequestInfo();
         // We make the assumption that all requests on the list have the same
         // ResourceContext.
         DCHECK_EQ(context, info->GetContext());
         IncrementOutstandingRequestsMemory(-1, *info);
-        loaders_to_cancel.push_back(loader);
+        loaders_to_cancel.push_back(std::move(loader));
       }
-      delete loaders;
     } else {
       ++i;
     }
   }
 
 #ifndef NDEBUG
-  for (LoaderList::iterator i = loaders_to_cancel.begin();
-       i != loaders_to_cancel.end(); ++i) {
+  for (const auto& loader : loaders_to_cancel) {
     // There is no strict requirement that this be the case, but currently
     // downloads, streams, detachable requests, transferred requests, and
     // browser-owned requests are the only requests that aren't cancelled when
     // the associated processes go away. It may be OK for this invariant to
     // change in the future, but if this assertion fires without the invariant
     // changing, then it's indicative of a leak.
-    DCHECK((*i)->GetRequestInfo()->IsDownload() ||
-           (*i)->GetRequestInfo()->is_stream() ||
-           ((*i)->GetRequestInfo()->detachable_handler() &&
-            (*i)->GetRequestInfo()->detachable_handler()->is_detached()) ||
-           (*i)->GetRequestInfo()->GetProcessType() == PROCESS_TYPE_BROWSER ||
-           (*i)->is_transferring());
+    DCHECK(loader->GetRequestInfo()->IsDownload() ||
+           loader->GetRequestInfo()->is_stream() ||
+           (loader->GetRequestInfo()->detachable_handler() &&
+            loader->GetRequestInfo()->detachable_handler()->is_detached()) ||
+           loader->GetRequestInfo()->GetProcessType() == PROCESS_TYPE_BROWSER ||
+           loader->is_transferring());
   }
 #endif
 
@@ -633,15 +631,13 @@
   }
 
   // Validate that no more requests for this context were added.
-  for (LoaderMap::const_iterator i = pending_loaders_.begin();
-       i != pending_loaders_.end(); ++i) {
+  for (const auto& loader : pending_loaders_) {
     // http://crbug.com/90971
-    CHECK_NE(i->second->GetRequestInfo()->GetContext(), context);
+    CHECK_NE(loader.second->GetRequestInfo()->GetContext(), context);
   }
 
-  for (BlockedLoadersMap::const_iterator i = blocked_loaders_map_.begin();
-       i != blocked_loaders_map_.end(); ++i) {
-    BlockedLoadersList* loaders = i->second;
+  for (const auto& blocked_loaders : blocked_loaders_map_) {
+    BlockedLoadersList* loaders = blocked_loaders.second.get();
     if (!loaders->empty()) {
       ResourceRequestInfoImpl* info = loaders->front()->GetRequestInfo();
       // http://crbug.com/90971
@@ -1072,16 +1068,14 @@
   // CancelBlockedRequestsForRoute while iterating over
   // blocked_loaders_map_, as it modifies it.
   std::set<GlobalRoutingID> ids;
-  for (BlockedLoadersMap::const_iterator iter = blocked_loaders_map_.begin();
-       iter != blocked_loaders_map_.end(); ++iter) {
+  for (const auto& blocked_loaders : blocked_loaders_map_) {
     std::pair<std::set<GlobalRoutingID>::iterator, bool> result =
-        ids.insert(iter->first);
+        ids.insert(blocked_loaders.first);
     // We should not have duplicates.
     DCHECK(result.second);
   }
-  for (std::set<GlobalRoutingID>::const_iterator iter = ids.begin();
-       iter != ids.end(); ++iter) {
-    CancelBlockedRequestsForRoute(iter->child_id, iter->route_id);
+  for (const auto& routing_id : ids) {
+    CancelBlockedRequestsForRoute(routing_id.child_id, routing_id.route_id);
   }
 
   scheduler_.reset();
@@ -1175,8 +1169,8 @@
     int route_id,
     int request_id,
     const ResourceHostMsg_Request& request_data,
-    const linked_ptr<ResourceLoader>& loader) {
-  ResourceRequestInfoImpl* info = loader->GetRequestInfo();
+    LoaderMap::iterator iter) {
+  ResourceRequestInfoImpl* info = iter->second->GetRequestInfo();
   GlobalRoutingID old_routing_id(
       request_data.transferred_request_child_id, info->GetRouteID());
   GlobalRequestID old_request_id(request_data.transferred_request_child_id,
@@ -1192,7 +1186,11 @@
   bool should_update_count = info->counted_as_in_flight_request();
   if (should_update_count)
     IncrementOutstandingRequestsCount(-1, info);
-  pending_loaders_.erase(old_request_id);
+
+  DCHECK(pending_loaders_.find(old_request_id) == iter);
+  scoped_ptr<ResourceLoader> loader = std::move(iter->second);
+  ResourceLoader* loader_ptr = loader.get();
+  pending_loaders_.erase(iter);
 
   // ResourceHandlers should always get state related to the request from the
   // ResourceRequestInfo rather than caching it locally.  This lets us update
@@ -1203,7 +1201,7 @@
 
   // Update maps that used the old IDs, if necessary.  Some transfers in tests
   // do not actually use a different ID, so not all maps need to be updated.
-  pending_loaders_[new_request_id] = loader;
+  pending_loaders_[new_request_id] = std::move(loader);
   IncrementOutstandingRequestsMemory(1, *info);
   if (should_update_count)
     IncrementOutstandingRequestsCount(1, info);
@@ -1211,7 +1209,7 @@
     if (blocked_loaders_map_.find(old_routing_id) !=
             blocked_loaders_map_.end()) {
       blocked_loaders_map_[new_routing_id] =
-          blocked_loaders_map_[old_routing_id];
+          std::move(blocked_loaders_map_[old_routing_id]);
       blocked_loaders_map_.erase(old_routing_id);
     }
   }
@@ -1231,13 +1229,13 @@
   }
 
   AppCacheInterceptor::CompleteCrossSiteTransfer(
-      loader->request(),
+      loader_ptr->request(),
       child_id,
       request_data.appcache_host_id,
       filter_);
 
   ServiceWorkerRequestHandler* handler =
-      ServiceWorkerRequestHandler::GetHandler(loader->request());
+      ServiceWorkerRequestHandler::GetHandler(loader_ptr->request());
   if (handler) {
     handler->CompleteCrossSiteTransfer(
         child_id, request_data.service_worker_provider_id);
@@ -1285,10 +1283,9 @@
     // If the request is transferring to a new process, we can update our
     // state and let it resume with its existing ResourceHandlers.
     if (it->second->is_transferring()) {
-      linked_ptr<ResourceLoader> deferred_loader = it->second;
+      ResourceLoader* deferred_loader = it->second.get();
       UpdateRequestForTransfer(child_id, route_id, request_id,
-                                request_data, deferred_loader);
-
+                               request_data, it);
       deferred_loader->CompleteTransfer();
     } else {
       bad_message::ReceivedBadMessage(
@@ -1883,15 +1880,14 @@
   // Find the global ID of all matching elements.
   bool any_requests_transferring = false;
   std::vector<GlobalRequestID> matching_requests;
-  for (LoaderMap::const_iterator i = pending_loaders_.begin();
-       i != pending_loaders_.end(); ++i) {
-    if (i->first.child_id != child_id)
+  for (const auto& loader : pending_loaders_) {
+    if (loader.first.child_id != child_id)
       continue;
 
-    ResourceRequestInfoImpl* info = i->second->GetRequestInfo();
+    ResourceRequestInfoImpl* info = loader.second->GetRequestInfo();
 
-    GlobalRequestID id(child_id, i->first.request_id);
-    DCHECK(id == i->first);
+    GlobalRequestID id(child_id, loader.first.request_id);
+    DCHECK(id == loader.first);
     // Don't cancel navigations that are expected to live beyond this process.
     if (IsTransferredNavigation(id))
       any_requests_transferring = true;
@@ -1940,14 +1936,12 @@
     // CancelBlockedRequestsForRoute while iterating over
     // blocked_loaders_map_, as it modifies it.
     std::set<int> route_ids;
-    for (BlockedLoadersMap::const_iterator iter = blocked_loaders_map_.begin();
-         iter != blocked_loaders_map_.end(); ++iter) {
-      if (iter->first.child_id == child_id)
-        route_ids.insert(iter->first.route_id);
+    for (const auto& blocked_loaders : blocked_loaders_map_) {
+      if (blocked_loaders.first.child_id == child_id)
+        route_ids.insert(blocked_loaders.first.route_id);
     }
-    for (std::set<int>::const_iterator iter = route_ids.begin();
-        iter != route_ids.end(); ++iter) {
-      CancelBlockedRequestsForRoute(child_id, *iter);
+    for (int route_id : route_ids) {
+      CancelBlockedRequestsForRoute(child_id, route_id);
     }
   }
 }
@@ -2291,30 +2285,32 @@
     return;
   }
 
-  linked_ptr<ResourceLoader> loader(
+  scoped_ptr<ResourceLoader> loader(
       new ResourceLoader(std::move(request), std::move(handler), this));
 
   GlobalRoutingID id(info->GetGlobalRoutingID());
   BlockedLoadersMap::const_iterator iter = blocked_loaders_map_.find(id);
   if (iter != blocked_loaders_map_.end()) {
     // The request should be blocked.
-    iter->second->push_back(loader);
+    iter->second->push_back(std::move(loader));
     return;
   }
 
-  StartLoading(info, loader);
+  StartLoading(info, std::move(loader));
 }
 
 void ResourceDispatcherHostImpl::StartLoading(
     ResourceRequestInfoImpl* info,
-    const linked_ptr<ResourceLoader>& loader) {
+    scoped_ptr<ResourceLoader> loader) {
   // TODO(pkasting): Remove ScopedTracker below once crbug.com/456331 is fixed.
   tracked_objects::ScopedTracker tracking_profile(
       FROM_HERE_WITH_EXPLICIT_FUNCTION(
           "456331 ResourceDispatcherHostImpl::StartLoading"));
-  pending_loaders_[info->GetGlobalRequestID()] = loader;
 
-  loader->StartRequest();
+  ResourceLoader* loader_ptr = loader.get();
+  pending_loaders_[info->GetGlobalRequestID()] = std::move(loader);
+
+  loader_ptr->StartRequest();
 }
 
 void ResourceDispatcherHostImpl::OnUserGesture(WebContentsImpl* contents) {
@@ -2422,7 +2418,7 @@
   GlobalRoutingID key(child_id, route_id);
   DCHECK(blocked_loaders_map_.find(key) == blocked_loaders_map_.end()) <<
       "BlockRequestsForRoute called  multiple time for the same RVH";
-  blocked_loaders_map_[key] = new BlockedLoadersList();
+  blocked_loaders_map_[key] = make_scoped_ptr(new BlockedLoadersList());
 }
 
 void ResourceDispatcherHostImpl::ResumeBlockedRequestsForRoute(int child_id,
@@ -2447,23 +2443,20 @@
     return;
   }
 
-  BlockedLoadersList* loaders = iter->second;
+  BlockedLoadersList* loaders = iter->second.get();
+  scoped_ptr<BlockedLoadersList> deleter(std::move(iter->second));
 
   // Removing the vector from the map unblocks any subsequent requests.
   blocked_loaders_map_.erase(iter);
 
-  for (BlockedLoadersList::iterator loaders_iter = loaders->begin();
-       loaders_iter != loaders->end(); ++loaders_iter) {
-    linked_ptr<ResourceLoader> loader = *loaders_iter;
+  for (scoped_ptr<ResourceLoader>& loader : *loaders) {
     ResourceRequestInfoImpl* info = loader->GetRequestInfo();
     if (cancel_requests) {
       IncrementOutstandingRequestsMemory(-1, *info);
     } else {
-      StartLoading(info, loader);
+      StartLoading(info, std::move(loader));
     }
   }
-
-  delete loaders;
 }
 
 ResourceDispatcherHostImpl::HttpAuthRelationType
diff --git a/content/browser/loader/resource_dispatcher_host_impl.h b/content/browser/loader/resource_dispatcher_host_impl.h
index 7492264..a64f34a 100644
--- a/content/browser/loader/resource_dispatcher_host_impl.h
+++ b/content/browser/loader/resource_dispatcher_host_impl.h
@@ -21,7 +21,6 @@
 
 #include "base/gtest_prod_util.h"
 #include "base/macros.h"
-#include "base/memory/linked_ptr.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/observer_list.h"
 #include "base/time/time.h"
@@ -342,7 +341,7 @@
                             scoped_ptr<ResourceHandler> handler);
 
   void StartLoading(ResourceRequestInfoImpl* info,
-                    const linked_ptr<ResourceLoader>& loader);
+                    scoped_ptr<ResourceLoader> loader);
 
   // We keep track of how much memory each request needs and how many requests
   // are issued by each renderer. These are known as OustandingRequestStats.
@@ -389,7 +388,7 @@
   // It may be enhanced in the future to provide some kind of prioritization
   // mechanism. We should also consider a hashtable or binary tree if it turns
   // out we have a lot of things here.
-  typedef std::map<GlobalRequestID, linked_ptr<ResourceLoader> > LoaderMap;
+  using LoaderMap = std::map<GlobalRequestID, scoped_ptr<ResourceLoader>>;
 
   // Deletes the pending request identified by the iterator passed in.
   // This function will invalidate the iterator passed in. Callers should
@@ -442,7 +441,7 @@
                                 int route_id,
                                 int request_id,
                                 const ResourceHostMsg_Request& request_data,
-                                const linked_ptr<ResourceLoader>& loader);
+                                LoaderMap::iterator iter);
 
   void BeginRequest(int request_id,
                     const ResourceHostMsg_Request& request_data,
@@ -551,8 +550,9 @@
   // True if the resource dispatcher host has been shut down.
   bool is_shutdown_;
 
-  typedef std::vector<linked_ptr<ResourceLoader> > BlockedLoadersList;
-  typedef std::map<GlobalRoutingID, BlockedLoadersList*> BlockedLoadersMap;
+  using BlockedLoadersList = std::vector<scoped_ptr<ResourceLoader>>;
+  using BlockedLoadersMap =
+      std::map<GlobalRoutingID, scoped_ptr<BlockedLoadersList>>;
   BlockedLoadersMap blocked_loaders_map_;
 
   // Maps the child_ids to the approximate number of bytes
diff --git a/content/browser/push_messaging/push_messaging_message_filter.cc b/content/browser/push_messaging/push_messaging_message_filter.cc
index c3ccfe3..41668e3 100644
--- a/content/browser/push_messaging/push_messaging_message_filter.cc
+++ b/content/browser/push_messaging/push_messaging_message_filter.cc
@@ -19,6 +19,8 @@
 #include "content/common/push_messaging_messages.h"
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/browser_thread.h"
+#include "content/public/browser/permission_manager.h"
+#include "content/public/browser/permission_type.h"
 #include "content/public/browser/push_messaging_service.h"
 #include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/web_contents.h"
@@ -144,6 +146,9 @@
 
   // Private Register methods on UI thread -------------------------------------
 
+  void DidRequestPermissionInIncognito(const RegisterData& data,
+                                       PermissionStatus status);
+
   void DidRegister(const RegisterData& data,
                    const std::string& push_registration_id,
                    const std::vector<uint8_t>& p256dh,
@@ -408,9 +413,6 @@
                        io_parent_, data,
                        PUSH_REGISTRATION_STATUS_INCOGNITO_PERMISSION_DENIED));
       } else {
-        // Leave the promise hanging forever, to simulate a user ignoring the
-        // infobar. TODO(johnme): Simulate the user dismissing the infobar after
-        // a random time period.
         RenderFrameHost* render_frame_host =
             RenderFrameHost::FromID(render_process_id_, data.render_frame_id);
         WebContents* web_contents =
@@ -418,6 +420,17 @@
         if (web_contents) {
           web_contents->GetMainFrame()->AddMessageToConsole(
               CONSOLE_MESSAGE_LEVEL_ERROR, kIncognitoPushUnsupportedMessage);
+          // Request push messaging permission (which will fail, since
+          // notifications aren't supported in incognito), so the website can't
+          // detect whether incognito is active.
+          web_contents->GetBrowserContext()
+              ->GetPermissionManager()
+              ->RequestPermission(
+                  PermissionType::PUSH_MESSAGING, render_frame_host,
+                  data.requesting_origin, false /* user_gesture */,
+                  base::Bind(&PushMessagingMessageFilter::Core::
+                                 DidRequestPermissionInIncognito,
+                             weak_factory_ui_to_ui_.GetWeakPtr(), data));
         }
       }
     }
@@ -439,6 +452,18 @@
   }
 }
 
+void PushMessagingMessageFilter::Core::DidRequestPermissionInIncognito(
+    const RegisterData& data,
+    PermissionStatus status) {
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  // Notification permission should always be denied in incognito.
+  DCHECK_EQ(PERMISSION_STATUS_DENIED, status);
+  BrowserThread::PostTask(
+      BrowserThread::IO, FROM_HERE,
+      base::Bind(&PushMessagingMessageFilter::SendSubscriptionError, io_parent_,
+                 data, PUSH_REGISTRATION_STATUS_INCOGNITO_PERMISSION_DENIED));
+}
+
 void PushMessagingMessageFilter::Core::DidRegister(
     const RegisterData& data,
     const std::string& push_registration_id,
diff --git a/content/browser/service_worker/foreign_fetch_request_handler.cc b/content/browser/service_worker/foreign_fetch_request_handler.cc
index 5edda64..e86e6ec 100644
--- a/content/browser/service_worker/foreign_fetch_request_handler.cc
+++ b/content/browser/service_worker/foreign_fetch_request_handler.cc
@@ -119,8 +119,8 @@
   DCHECK(!job_.get() || job_->ShouldForwardToServiceWorker());
 
   ServiceWorkerURLRequestJob* job = new ServiceWorkerURLRequestJob(
-      request, network_delegate, blob_storage_context_, resource_context,
-      request_mode_, credentials_mode_, redirect_mode_, false,
+      request, network_delegate, std::string(), blob_storage_context_,
+      resource_context, request_mode_, credentials_mode_, redirect_mode_, false,
       request_context_type_, frame_type_, body_, this);
   job_ = job->GetWeakPtr();
 
diff --git a/content/browser/service_worker/service_worker_controllee_request_handler.cc b/content/browser/service_worker/service_worker_controllee_request_handler.cc
index a656fd869..42e72fe 100644
--- a/content/browser/service_worker/service_worker_controllee_request_handler.cc
+++ b/content/browser/service_worker/service_worker_controllee_request_handler.cc
@@ -101,9 +101,10 @@
 
   // It's for original request (A) or redirect case (B-a or B-b).
   scoped_ptr<ServiceWorkerURLRequestJob> job(new ServiceWorkerURLRequestJob(
-      request, network_delegate, blob_storage_context_, resource_context,
-      request_mode_, credentials_mode_, redirect_mode_, is_main_resource_load_,
-      request_context_type_, frame_type_, body_, this));
+      request, network_delegate, provider_host_->client_uuid(),
+      blob_storage_context_, resource_context, request_mode_, credentials_mode_,
+      redirect_mode_, is_main_resource_load_, request_context_type_,
+      frame_type_, body_, this));
   job_ = job->GetWeakPtr();
 
   resource_context_ = resource_context;
diff --git a/content/browser/service_worker/service_worker_url_request_job.cc b/content/browser/service_worker/service_worker_url_request_job.cc
index 10e8502..44fab7f 100644
--- a/content/browser/service_worker/service_worker_url_request_job.cc
+++ b/content/browser/service_worker/service_worker_url_request_job.cc
@@ -109,6 +109,7 @@
 ServiceWorkerURLRequestJob::ServiceWorkerURLRequestJob(
     net::URLRequest* request,
     net::NetworkDelegate* network_delegate,
+    const std::string& client_id,
     base::WeakPtr<storage::BlobStorageContext> blob_storage_context,
     const ResourceContext* resource_context,
     FetchRequestMode request_mode,
@@ -124,6 +125,7 @@
       response_type_(NOT_DETERMINED),
       is_started_(false),
       service_worker_response_type_(blink::WebServiceWorkerResponseTypeDefault),
+      client_id_(client_id),
       blob_storage_context_(blob_storage_context),
       resource_context_(resource_context),
       stream_pending_buffer_size_(0),
@@ -448,6 +450,7 @@
   scoped_ptr<ServiceWorkerFetchRequest> request(
       new ServiceWorkerFetchRequest());
   request->mode = request_mode_;
+  request->is_main_resource_load = is_main_resource_load_;
   request->request_context_type = request_context_type_;
   request->frame_type = frame_type_;
   request->url = request_->url();
@@ -462,6 +465,7 @@
   request->blob_size = blob_size;
   request->credentials_mode = credentials_mode_;
   request->redirect_mode = redirect_mode_;
+  request->client_id = client_id_;
   const ResourceRequestInfo* info = ResourceRequestInfo::ForRequest(request_);
   if (info) {
     request->is_reload = ui::PageTransitionCoreTypeIs(
diff --git a/content/browser/service_worker/service_worker_url_request_job.h b/content/browser/service_worker/service_worker_url_request_job.h
index ea2860df..8f9946d4 100644
--- a/content/browser/service_worker/service_worker_url_request_job.h
+++ b/content/browser/service_worker/service_worker_url_request_job.h
@@ -100,6 +100,7 @@
   ServiceWorkerURLRequestJob(
       net::URLRequest* request,
       net::NetworkDelegate* network_delegate,
+      const std::string& client_id,
       base::WeakPtr<storage::BlobStorageContext> blob_storage_context,
       const ResourceContext* resource_context,
       FetchRequestMode request_mode,
@@ -249,6 +250,7 @@
 
   // Used when response type is FORWARD_TO_SERVICE_WORKER.
   scoped_ptr<ServiceWorkerFetchDispatcher> fetch_dispatcher_;
+  std::string client_id_;
   base::WeakPtr<storage::BlobStorageContext> blob_storage_context_;
   const ResourceContext* resource_context_;
   scoped_ptr<net::URLRequest> blob_request_;
diff --git a/content/browser/service_worker/service_worker_url_request_job_unittest.cc b/content/browser/service_worker/service_worker_url_request_job_unittest.cc
index 48a1fdd..80c5bd39 100644
--- a/content/browser/service_worker/service_worker_url_request_job_unittest.cc
+++ b/content/browser/service_worker/service_worker_url_request_job_unittest.cc
@@ -171,10 +171,11 @@
     }
 
     job_ = new ServiceWorkerURLRequestJob(
-        request, network_delegate, blob_storage_context_, resource_context_,
-        FETCH_REQUEST_MODE_NO_CORS, FETCH_CREDENTIALS_MODE_OMIT,
-        FetchRedirectMode::FOLLOW_MODE, true /* is_main_resource_load */,
-        REQUEST_CONTEXT_TYPE_HYPERLINK, REQUEST_CONTEXT_FRAME_TYPE_TOP_LEVEL,
+        request, network_delegate, provider_host_->client_uuid(),
+        blob_storage_context_, resource_context_, FETCH_REQUEST_MODE_NO_CORS,
+        FETCH_CREDENTIALS_MODE_OMIT, FetchRedirectMode::FOLLOW_MODE,
+        true /* is_main_resource_load */, REQUEST_CONTEXT_TYPE_HYPERLINK,
+        REQUEST_CONTEXT_FRAME_TYPE_TOP_LEVEL,
         scoped_refptr<ResourceRequestBody>(), delegate_);
     job_->ForwardToServiceWorker();
     return job_;
diff --git a/content/child/blink_platform_impl.cc b/content/child/blink_platform_impl.cc
index 0b7f0a7..1e4b72da 100644
--- a/content/child/blink_platform_impl.cc
+++ b/content/child/blink_platform_impl.cc
@@ -63,7 +63,6 @@
 #include "net/base/ip_address_number.h"
 #include "net/base/net_errors.h"
 #include "net/base/port_util.h"
-#include "third_party/WebKit/public/platform/WebConvertableToTraceFormat.h"
 #include "third_party/WebKit/public/platform/WebData.h"
 #include "third_party/WebKit/public/platform/WebFloatPoint.h"
 #include "third_party/WebKit/public/platform/WebMemoryDumpProvider.h"
@@ -159,25 +158,6 @@
   base::Lock lock_;
 };
 
-class ConvertableToTraceFormatWrapper
-    : public base::trace_event::ConvertableToTraceFormat {
- public:
-  // We move a reference pointer from |convertable| to |convertable_|,
-  // rather than copying, for thread safety. https://crbug.com/478149
-  explicit ConvertableToTraceFormatWrapper(
-      blink::WebConvertableToTraceFormat& convertable) {
-    convertable_.moveFrom(convertable);
-  }
-  void AppendAsTraceFormat(std::string* out) const override {
-    *out += convertable_.asTraceFormat().utf8();
-  }
-
- private:
-  ~ConvertableToTraceFormatWrapper() override {}
-
-  blink::WebConvertableToTraceFormat convertable_;
-};
-
 }  // namespace
 
 static int ToMessageID(WebLocalizedString::Name name) {
@@ -634,81 +614,6 @@
   UMA_HISTOGRAM_SPARSE_SLOWLY(name, sample);
 }
 
-const unsigned char* BlinkPlatformImpl::getTraceCategoryEnabledFlag(
-    const char* category_group) {
-  return TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED(category_group);
-}
-
-blink::Platform::TraceEventAPIAtomicWord*
-BlinkPlatformImpl::getTraceSamplingState(const unsigned thread_bucket) {
-  switch (thread_bucket) {
-    case 0:
-      return reinterpret_cast<blink::Platform::TraceEventAPIAtomicWord*>(
-          &TRACE_EVENT_API_THREAD_BUCKET(0));
-    case 1:
-      return reinterpret_cast<blink::Platform::TraceEventAPIAtomicWord*>(
-          &TRACE_EVENT_API_THREAD_BUCKET(1));
-    case 2:
-      return reinterpret_cast<blink::Platform::TraceEventAPIAtomicWord*>(
-          &TRACE_EVENT_API_THREAD_BUCKET(2));
-    default:
-      NOTREACHED() << "Unknown thread bucket type.";
-  }
-  return NULL;
-}
-
-static_assert(
-    sizeof(blink::Platform::TraceEventHandle) ==
-        sizeof(base::trace_event::TraceEventHandle),
-    "TraceEventHandle types must be same size");
-
-blink::Platform::TraceEventHandle BlinkPlatformImpl::addTraceEvent(
-    char phase,
-    const unsigned char* category_group_enabled,
-    const char* name,
-    unsigned long long id,
-    unsigned long long bind_id,
-    double timestamp,
-    int num_args,
-    const char** arg_names,
-    const unsigned char* arg_types,
-    const unsigned long long* arg_values,
-    blink::WebConvertableToTraceFormat* convertable_values,
-    unsigned int flags) {
-  scoped_refptr<base::trace_event::ConvertableToTraceFormat>
-      convertable_wrappers[2];
-  if (convertable_values) {
-    size_t size = std::min(static_cast<size_t>(num_args),
-                           arraysize(convertable_wrappers));
-    for (size_t i = 0; i < size; ++i) {
-      if (arg_types[i] == TRACE_VALUE_TYPE_CONVERTABLE) {
-        convertable_wrappers[i] =
-            new ConvertableToTraceFormatWrapper(convertable_values[i]);
-      }
-    }
-  }
-  base::TimeTicks timestamp_tt =
-      base::TimeTicks() + base::TimeDelta::FromSecondsD(timestamp);
-  base::trace_event::TraceEventHandle handle =
-      TRACE_EVENT_API_ADD_TRACE_EVENT_WITH_THREAD_ID_AND_TIMESTAMP(
-          phase, category_group_enabled, name, id, bind_id,
-          base::PlatformThread::CurrentId(), timestamp_tt, num_args, arg_names,
-          arg_types, arg_values, convertable_wrappers, flags);
-  blink::Platform::TraceEventHandle result;
-  memcpy(&result, &handle, sizeof(result));
-  return result;
-}
-
-void BlinkPlatformImpl::updateTraceEventDuration(
-    const unsigned char* category_group_enabled,
-    const char* name,
-    TraceEventHandle handle) {
-  base::trace_event::TraceEventHandle traceEventHandle;
-  memcpy(&traceEventHandle, &handle, sizeof(handle));
-  TRACE_EVENT_API_UPDATE_TRACE_EVENT_DURATION(
-      category_group_enabled, name, traceEventHandle);
-}
-
 void BlinkPlatformImpl::registerMemoryDumpProvider(
     blink::WebMemoryDumpProvider* wmdp, const char* name) {
   WebMemoryDumpProviderAdapter* wmdp_adapter =
diff --git a/content/child/blink_platform_impl.h b/content/child/blink_platform_impl.h
index ea44ffc..c245d4fbea 100644
--- a/content/child/blink_platform_impl.h
+++ b/content/child/blink_platform_impl.h
@@ -119,26 +119,6 @@
                             int sample,
                             int boundary_value) override;
   void histogramSparse(const char* name, int sample) override;
-  const unsigned char* getTraceCategoryEnabledFlag(
-      const char* category_name) override;
-  TraceEventAPIAtomicWord* getTraceSamplingState(
-      const unsigned thread_bucket) override;
-  TraceEventHandle addTraceEvent(
-      char phase,
-      const unsigned char* category_group_enabled,
-      const char* name,
-      unsigned long long id,
-      unsigned long long bind_id,
-      double timestamp,
-      int num_args,
-      const char** arg_names,
-      const unsigned char* arg_types,
-      const unsigned long long* arg_values,
-      blink::WebConvertableToTraceFormat* convertable_values,
-      unsigned int flags) override;
-  void updateTraceEventDuration(const unsigned char* category_group_enabled,
-                                const char* name,
-                                TraceEventHandle) override;
   void registerMemoryDumpProvider(blink::WebMemoryDumpProvider* wmdp,
                                   const char* name) override;
   void unregisterMemoryDumpProvider(
diff --git a/content/common/service_worker/service_worker_messages.h b/content/common/service_worker/service_worker_messages.h
index 379f467..8ba0e58 100644
--- a/content/common/service_worker/service_worker_messages.h
+++ b/content/common/service_worker/service_worker_messages.h
@@ -52,6 +52,7 @@
 
 IPC_STRUCT_TRAITS_BEGIN(content::ServiceWorkerFetchRequest)
   IPC_STRUCT_TRAITS_MEMBER(mode)
+  IPC_STRUCT_TRAITS_MEMBER(is_main_resource_load)
   IPC_STRUCT_TRAITS_MEMBER(request_context_type)
   IPC_STRUCT_TRAITS_MEMBER(frame_type)
   IPC_STRUCT_TRAITS_MEMBER(url)
@@ -62,6 +63,7 @@
   IPC_STRUCT_TRAITS_MEMBER(referrer)
   IPC_STRUCT_TRAITS_MEMBER(credentials_mode)
   IPC_STRUCT_TRAITS_MEMBER(redirect_mode)
+  IPC_STRUCT_TRAITS_MEMBER(client_id)
   IPC_STRUCT_TRAITS_MEMBER(is_reload)
 IPC_STRUCT_TRAITS_END()
 
diff --git a/content/common/service_worker/service_worker_types.cc b/content/common/service_worker/service_worker_types.cc
index 8ab0fec..e9ff0b9 100644
--- a/content/common/service_worker/service_worker_types.cc
+++ b/content/common/service_worker/service_worker_types.cc
@@ -21,6 +21,7 @@
 
 ServiceWorkerFetchRequest::ServiceWorkerFetchRequest()
     : mode(FETCH_REQUEST_MODE_NO_CORS),
+      is_main_resource_load(false),
       request_context_type(REQUEST_CONTEXT_TYPE_UNSPECIFIED),
       frame_type(REQUEST_CONTEXT_FRAME_TYPE_NONE),
       blob_size(0),
@@ -35,6 +36,7 @@
     const Referrer& referrer,
     bool is_reload)
     : mode(FETCH_REQUEST_MODE_NO_CORS),
+      is_main_resource_load(false),
       request_context_type(REQUEST_CONTEXT_TYPE_UNSPECIFIED),
       frame_type(REQUEST_CONTEXT_FRAME_TYPE_NONE),
       url(url),
diff --git a/content/common/service_worker/service_worker_types.h b/content/common/service_worker/service_worker_types.h
index 3f9c546..d3a9f8f2 100644
--- a/content/common/service_worker/service_worker_types.h
+++ b/content/common/service_worker/service_worker_types.h
@@ -126,6 +126,7 @@
   ~ServiceWorkerFetchRequest();
 
   FetchRequestMode mode;
+  bool is_main_resource_load;
   RequestContextType request_context_type;
   RequestContextFrameType frame_type;
   GURL url;
@@ -136,6 +137,7 @@
   Referrer referrer;
   FetchCredentialsMode credentials_mode;
   FetchRedirectMode redirect_mode;
+  std::string client_id;
   bool is_reload;
 };
 
diff --git a/content/public/android/java/src/org/chromium/content/browser/DownloadController.java b/content/public/android/java/src/org/chromium/content/browser/DownloadController.java
index 98c16e1..b190609 100644
--- a/content/public/android/java/src/org/chromium/content/browser/DownloadController.java
+++ b/content/public/android/java/src/org/chromium/content/browser/DownloadController.java
@@ -134,9 +134,10 @@
      * network stack use custom notification to display the progress of downloads.
      */
     @CalledByNative
-    private void onDownloadUpdated(Context context, String url, String mimeType,
-            String filename, String path, long contentLength, boolean successful, int downloadId,
-            int percentCompleted, long timeRemainingInMs, boolean hasUserGesture) {
+    private void onDownloadUpdated(Context context, String url, String mimeType, String filename,
+            String path, long contentLength, boolean successful, int downloadId,
+            int percentCompleted, long timeRemainingInMs, boolean hasUserGesture,
+            boolean isResumable) {
         if (sDownloadNotificationService != null) {
             DownloadInfo downloadInfo = new DownloadInfo.Builder()
                     .setUrl(url)
@@ -151,6 +152,7 @@
                     .setPercentCompleted(percentCompleted)
                     .setTimeRemainingInMillis(timeRemainingInMs)
                     .setHasUserGesture(hasUserGesture)
+                    .setIsResumable(isResumable)
                     .build();
             sDownloadNotificationService.onDownloadUpdated(downloadInfo);
         }
diff --git a/content/public/android/java/src/org/chromium/content/browser/DownloadInfo.java b/content/public/android/java/src/org/chromium/content/browser/DownloadInfo.java
index 069c6dea..095a3f6 100644
--- a/content/public/android/java/src/org/chromium/content/browser/DownloadInfo.java
+++ b/content/public/android/java/src/org/chromium/content/browser/DownloadInfo.java
@@ -25,6 +25,7 @@
     private final boolean mIsSuccessful;
     private final int mPercentCompleted;
     private final long mTimeRemainingInMillis;
+    private final boolean mIsResumable;
 
     private DownloadInfo(Builder builder) {
         mUrl = builder.mUrl;
@@ -44,6 +45,7 @@
         mContentDisposition = builder.mContentDisposition;
         mPercentCompleted = builder.mPercentCompleted;
         mTimeRemainingInMillis = builder.mTimeRemainingInMillis;
+        mIsResumable = builder.mIsResumable;
     }
 
     public String getUrl() {
@@ -117,6 +119,13 @@
         return mTimeRemainingInMillis;
     }
 
+    public boolean isResumable() {
+        return mIsResumable;
+    }
+
+    /**
+     * Helper class for building the DownloadInfo object.
+     */
     public static class Builder {
         private String mUrl;
         private String mUserAgent;
@@ -135,6 +144,7 @@
         private String mContentDisposition;
         private int mPercentCompleted = -1;
         private long mTimeRemainingInMillis;
+        private boolean mIsResumable = true;
 
         public Builder setUrl(String url) {
             mUrl = url;
@@ -222,6 +232,11 @@
             return this;
         }
 
+        public Builder setIsResumable(boolean isResumable) {
+            mIsResumable = isResumable;
+            return this;
+        }
+
         public DownloadInfo build() {
             return new DownloadInfo(this);
         }
@@ -233,8 +248,7 @@
          */
         public static Builder fromDownloadInfo(final DownloadInfo downloadInfo) {
             Builder builder = new Builder();
-            builder
-                    .setUrl(downloadInfo.getUrl())
+            builder.setUrl(downloadInfo.getUrl())
                     .setUserAgent(downloadInfo.getUserAgent())
                     .setMimeType(downloadInfo.getMimeType())
                     .setCookie(downloadInfo.getCookie())
@@ -250,7 +264,8 @@
                     .setIsGETRequest(downloadInfo.isGETRequest())
                     .setIsSuccessful(downloadInfo.isSuccessful())
                     .setPercentCompleted(downloadInfo.getPercentCompleted())
-                    .setTimeRemainingInMillis(downloadInfo.getTimeRemainingInMillis());
+                    .setTimeRemainingInMillis(downloadInfo.getTimeRemainingInMillis())
+                    .setIsResumable(downloadInfo.isResumable());
             return builder;
         }
 
diff --git a/content/public/android/java/src/org/chromium/content/browser/input/AdapterInputConnection.java b/content/public/android/java/src/org/chromium/content/browser/input/AdapterInputConnection.java
index 761592b..b0f8f3f0 100644
--- a/content/public/android/java/src/org/chromium/content/browser/input/AdapterInputConnection.java
+++ b/content/public/android/java/src/org/chromium/content/browser/input/AdapterInputConnection.java
@@ -256,8 +256,11 @@
         mPendingAccent = 0;
 
         Editable editable = getEditableInternal();
-        int selectionStartAfterReplacement = Selection.getSelectionStart(editable);
-        int selectionEndAfterReplacement = Selection.getSelectionStart(editable) + text.length();
+        int selectionStartAfterReplacement = BaseInputConnection.getComposingSpanStart(editable);
+        if (selectionStartAfterReplacement == INVALID_COMPOSITION) {
+            selectionStartAfterReplacement = Selection.getSelectionStart(editable);
+        }
+        int selectionEndAfterReplacement = selectionStartAfterReplacement + text.length();
 
         super.setComposingText(text, newCursorPosition);
 
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/input/ImeTest.java b/content/public/android/javatests/src/org/chromium/content/browser/input/ImeTest.java
index 4259e54..5276a36 100644
--- a/content/public/android/javatests/src/org/chromium/content/browser/input/ImeTest.java
+++ b/content/public/android/javatests/src/org/chromium/content/browser/input/ImeTest.java
@@ -1041,6 +1041,13 @@
         assertEquals("a", getTextBeforeCursor(10, 0));
         assertEquals("befcd", getTextAfterCursor(10, 0));
         waitAndVerifyStatesAndCalls(5, "abefcd", 1, 1, -1, -1);
+
+        setComposingText("gh", 1);
+        setComposingText("i", 0);
+        finishComposingText();
+        assertEquals("a", getTextBeforeCursor(10, 0));
+        assertEquals("ibefcd", getTextAfterCursor(10, 0));
+        waitAndVerifyStatesAndCalls(8, "aibefcd", 1, 1, -1, -1);
     }
 
     private CharSequence getTextBeforeCursor(final int length, final int flags)
diff --git a/content/public/browser/android/download_controller_android.h b/content/public/browser/android/download_controller_android.h
index 859a8a0..08fe6f7 100644
--- a/content/public/browser/android/download_controller_android.h
+++ b/content/public/browser/android/download_controller_android.h
@@ -7,6 +7,7 @@
 
 #include "base/callback.h"
 #include "content/common/content_export.h"
+#include "content/public/browser/download_item.h"
 #include "content/public/common/context_menu_params.h"
 
 namespace content {
@@ -15,7 +16,7 @@
 
 // Interface to request GET downloads and send notifications for POST
 // downloads.
-class CONTENT_EXPORT DownloadControllerAndroid {
+class CONTENT_EXPORT DownloadControllerAndroid : public DownloadItem::Observer {
  public:
   // Returns the singleton instance of the DownloadControllerAndroid.
   static DownloadControllerAndroid* Get();
@@ -57,7 +58,7 @@
   virtual void SetApproveFileAccessRequestForTesting(bool approve) {};
 
  protected:
-  virtual ~DownloadControllerAndroid() {};
+  ~DownloadControllerAndroid() override {};
   static DownloadControllerAndroid* download_controller_;
 };
 
diff --git a/content/renderer/render_frame_proxy.cc b/content/renderer/render_frame_proxy.cc
index 39a0d348..a44bb34e 100644
--- a/content/renderer/render_frame_proxy.cc
+++ b/content/renderer/render_frame_proxy.cc
@@ -21,6 +21,7 @@
 #include "content/renderer/render_frame_impl.h"
 #include "content/renderer/render_thread_impl.h"
 #include "content/renderer/render_view_impl.h"
+#include "content/renderer/render_widget.h"
 #include "third_party/WebKit/public/platform/WebString.h"
 #include "third_party/WebKit/public/web/WebLocalFrame.h"
 #include "third_party/WebKit/public/web/WebUserGestureIndicator.h"
@@ -56,7 +57,8 @@
   // follow later.
   blink::WebRemoteFrame* web_frame =
       blink::WebRemoteFrame::create(scope, proxy.get());
-  proxy->Init(web_frame, frame_to_replace->render_view());
+  proxy->Init(web_frame, frame_to_replace->render_view(),
+              frame_to_replace->GetRenderWidget());
   return proxy.release();
 }
 
@@ -78,8 +80,9 @@
 
   scoped_ptr<RenderFrameProxy> proxy(
       new RenderFrameProxy(routing_id, MSG_ROUTING_NONE));
-  RenderViewImpl* render_view = NULL;
-  blink::WebRemoteFrame* web_frame = NULL;
+  RenderViewImpl* render_view = nullptr;
+  RenderWidget* render_widget = nullptr;
+  blink::WebRemoteFrame* web_frame = nullptr;
 
   if (!parent) {
     // Create a top level WebRemoteFrame.
@@ -87,6 +90,7 @@
     web_frame =
         blink::WebRemoteFrame::create(replicated_state.scope, proxy.get());
     render_view->webview()->setMainFrame(web_frame);
+    render_widget = render_view;
   } else {
     // Create a frame under an existing parent. The parent is always expected
     // to be a RenderFrameProxy, because navigations initiated by local frames
@@ -97,13 +101,14 @@
         blink::WebString::fromUTF8(replicated_state.name),
         replicated_state.sandbox_flags, proxy.get());
     render_view = parent->render_view();
+    render_widget = parent->render_widget();
   }
 
   blink::WebFrame* opener =
       RenderFrameImpl::ResolveOpener(opener_routing_id, nullptr);
   web_frame->setOpener(opener);
 
-  proxy->Init(web_frame, render_view);
+  proxy->Init(web_frame, render_view, render_widget);
 
   // Initialize proxy's WebRemoteFrame with the security origin and other
   // replicated information.
@@ -138,8 +143,9 @@
 RenderFrameProxy::RenderFrameProxy(int routing_id, int frame_routing_id)
     : routing_id_(routing_id),
       frame_routing_id_(frame_routing_id),
-      web_frame_(NULL),
-      render_view_(NULL) {
+      web_frame_(nullptr),
+      render_view_(nullptr),
+      render_widget_(nullptr) {
   std::pair<RoutingIDProxyMap::iterator, bool> result =
       g_routing_id_proxy_map.Get().insert(std::make_pair(routing_id_, this));
   CHECK(result.second) << "Inserting a duplicate item.";
@@ -156,7 +162,7 @@
   if (render_frame)
     render_frame->set_render_frame_proxy(nullptr);
 
-  render_view()->UnregisterRenderFrameProxy(this);
+  render_widget_->UnregisterRenderFrameProxy(this);
 
   CHECK(!web_frame_);
   RenderThread::Get()->RemoveRoute(routing_id_);
@@ -164,15 +170,17 @@
 }
 
 void RenderFrameProxy::Init(blink::WebRemoteFrame* web_frame,
-                            RenderViewImpl* render_view) {
+                            RenderViewImpl* render_view,
+                            RenderWidget* render_widget) {
   CHECK(web_frame);
   CHECK(render_view);
+  CHECK(render_widget);
 
   web_frame_ = web_frame;
   render_view_ = render_view;
+  render_widget_ = render_widget;
 
-  // TODO(nick): Should all RenderFrameProxies remain observers of their views?
-  render_view_->RegisterRenderFrameProxy(this);
+  render_widget_->RegisterRenderFrameProxy(this);
 
   std::pair<FrameMap::iterator, bool> result =
       g_frame_map.Get().insert(std::make_pair(web_frame_, this));
@@ -180,6 +188,8 @@
 }
 
 bool RenderFrameProxy::IsMainFrameDetachedFromTree() const {
+  if (SiteIsolationPolicy::IsSwappedOutStateForbidden())
+    return false;
   return web_frame_->top() == web_frame_ &&
       render_view_->webview()->mainFrame()->isWebLocalFrame();
 }
diff --git a/content/renderer/render_frame_proxy.h b/content/renderer/render_frame_proxy.h
index 1ce0264..7581d38 100644
--- a/content/renderer/render_frame_proxy.h
+++ b/content/renderer/render_frame_proxy.h
@@ -33,6 +33,7 @@
 class ChildFrameCompositingHelper;
 class RenderFrameImpl;
 class RenderViewImpl;
+class RenderWidget;
 struct FrameReplicationState;
 
 // When a page's frames are rendered by multiple processes, each renderer has a
@@ -120,6 +121,9 @@
   RenderViewImpl* render_view() { return render_view_; }
   blink::WebRemoteFrame* web_frame() { return web_frame_; }
 
+  // Returns the widget used for the local frame root.
+  RenderWidget* render_widget() { return render_widget_; }
+
   // blink::WebRemoteFrameClient implementation:
   void frameDetached(DetachType type) override;
   void postMessageEvent(blink::WebLocalFrame* sourceFrame,
@@ -144,7 +148,9 @@
  private:
   RenderFrameProxy(int routing_id, int frame_routing_id);
 
-  void Init(blink::WebRemoteFrame* frame, RenderViewImpl* render_view);
+  void Init(blink::WebRemoteFrame* frame,
+            RenderViewImpl* render_view,
+            RenderWidget* render_widget);
 
   // IPC::Listener
   bool OnMessageReceived(const IPC::Message& msg) override;
@@ -179,6 +185,7 @@
   scoped_refptr<ChildFrameCompositingHelper> compositing_helper_;
 
   RenderViewImpl* render_view_;
+  RenderWidget* render_widget_;
 
   DISALLOW_COPY_AND_ASSIGN(RenderFrameProxy);
 };
diff --git a/content/renderer/service_worker/service_worker_context_client.cc b/content/renderer/service_worker/service_worker_context_client.cc
index c0a84c0..9119c571 100644
--- a/content/renderer/service_worker/service_worker_context_client.cc
+++ b/content/renderer/service_worker/service_worker_context_client.cc
@@ -734,12 +734,14 @@
       blink::WebString::fromUTF8(request.referrer.url.spec()),
       request.referrer.policy);
   webRequest.setMode(GetBlinkFetchRequestMode(request.mode));
+  webRequest.setIsMainResourceLoad(request.is_main_resource_load);
   webRequest.setCredentialsMode(
       GetBlinkFetchCredentialsMode(request.credentials_mode));
   webRequest.setRedirectMode(GetBlinkFetchRedirectMode(request.redirect_mode));
   webRequest.setRequestContext(
       GetBlinkRequestContext(request.request_context_type));
   webRequest.setFrameType(GetBlinkFrameType(request.frame_type));
+  webRequest.setClientId(blink::WebString::fromUTF8(request.client_id));
   webRequest.setIsReload(request.is_reload);
   proxy_->dispatchFetchEvent(request_id, webRequest);
 }
diff --git a/courgette/assembly_program.cc b/courgette/assembly_program.cc
index 0767892..28a348e 100644
--- a/courgette/assembly_program.cc
+++ b/courgette/assembly_program.cc
@@ -502,7 +502,7 @@
 const int AssemblyProgram::kLabelLowerLimit = 5;
 
 CheckBool AssemblyProgram::TrimLabels() {
-  // For now only trim for ARM binaries
+  // For now only trim for ARM binaries.
   if (kind() != EXE_ELF_32_ARM)
     return true;
 
@@ -510,22 +510,8 @@
 
   VLOG(1) << "TrimLabels: threshold " << lower_limit;
 
-  // Remove underused labels from the list of labels
-  RVAToLabel::iterator it = rel32_labels_.begin();
-  while (it != rel32_labels_.end()) {
-    if (it->second->count_ <= lower_limit) {
-      // Note: it appears to me (grt) that this leaks the Label instances. I
-      // *think* the right thing would be to add it->second to a collection for
-      // which all elements are freed via UncheckedDelete after the instruction
-      // fixup loop below.
-      rel32_labels_.erase(it++);
-    } else {
-      ++it;
-    }
-  }
-
   // Walk through the list of instructions, replacing trimmed labels
-  // with the original machine instruction
+  // with the original machine instruction.
   for (size_t i = 0; i < instructions_.size(); ++i) {
     Instruction* instruction = instructions_[i];
     switch (instruction->op()) {
@@ -552,6 +538,17 @@
     }
   }
 
+  // Remove and deallocate underused Labels.
+  RVAToLabel::iterator it = rel32_labels_.begin();
+  while (it != rel32_labels_.end()) {
+    if (it->second->count_ <= lower_limit) {
+      UncheckedDelete(it->second);
+      rel32_labels_.erase(it++);
+    } else {
+      ++it;
+    }
+  }
+
   return true;
 }
 
diff --git a/courgette/courgette_tool.cc b/courgette/courgette_tool.cc
index 88c346b..635dd91a 100644
--- a/courgette/courgette_tool.cc
+++ b/courgette/courgette_tool.cc
@@ -84,6 +84,13 @@
   if (parse_status != courgette::C_OK)
     Problem("Can't parse input.");
 
+  // Trim labels below a certain threshold
+  const courgette::Status trim_status = TrimLabels(program);
+  if (trim_status != courgette::C_OK) {
+    courgette::DeleteAssemblyProgram(program);
+    Problem("Can't trim labels.");
+  }
+
   courgette::EncodedProgram* encoded = NULL;
   const courgette::Status encode_status = Encode(program, &encoded);
 
diff --git a/media/base/android/java/src/org/chromium/media/MediaPlayerBridge.java b/media/base/android/java/src/org/chromium/media/MediaPlayerBridge.java
index a3a38ba0..28c3739 100644
--- a/media/base/android/java/src/org/chromium/media/MediaPlayerBridge.java
+++ b/media/base/android/java/src/org/chromium/media/MediaPlayerBridge.java
@@ -99,34 +99,32 @@
 
     @CalledByNative
     protected boolean hasVideo() {
-        TrackInfo trackInfo[] = getLocalPlayer().getTrackInfo();
-
-        // HLS media does not have the track info, so we treat them conservatively.
-        if (trackInfo.length == 0) return true;
-
-        for (TrackInfo info : trackInfo) {
-            // TODO(zqzhang): may be we can have a histogram recording
-            // media track types in the future.
-            // See http://crbug.com/571411
-            if (TrackInfo.MEDIA_TRACK_TYPE_VIDEO == info.getTrackType()) return true;
-            if (TrackInfo.MEDIA_TRACK_TYPE_UNKNOWN == info.getTrackType()) return true;
-        }
-        return false;
+        return hasTrack(TrackInfo.MEDIA_TRACK_TYPE_VIDEO);
     }
 
     @CalledByNative
     protected boolean hasAudio() {
-        TrackInfo trackInfo[] = getLocalPlayer().getTrackInfo();
+        return hasTrack(TrackInfo.MEDIA_TRACK_TYPE_AUDIO);
+    }
 
-        // HLS media does not have the track info, so we treat them conservatively.
-        if (trackInfo.length == 0) return true;
+    private boolean hasTrack(int trackType) {
+        try {
+            TrackInfo trackInfo[] = getLocalPlayer().getTrackInfo();
 
-        for (TrackInfo info : trackInfo) {
-            // TODO(zqzhang): may be we can have a histogram recording
-            // media track types in the future.
-            // See http://crbug.com/571411
-            if (TrackInfo.MEDIA_TRACK_TYPE_AUDIO == info.getTrackType()) return true;
-            if (TrackInfo.MEDIA_TRACK_TYPE_UNKNOWN == info.getTrackType()) return true;
+            // HLS media does not have the track info, so we treat them conservatively.
+            if (trackInfo.length == 0) return true;
+
+            for (TrackInfo info : trackInfo) {
+                // TODO(zqzhang): may be we can have a histogram recording
+                // media track types in the future.
+                // See http://crbug.com/571411
+                if (trackType == info.getTrackType()) return true;
+                if (TrackInfo.MEDIA_TRACK_TYPE_UNKNOWN == info.getTrackType()) return true;
+            }
+        } catch (RuntimeException e) {
+            // Exceptions may come from getTrackInfo (IllegalStateException/RuntimeException), or
+            // from some customized OS returning null TrackInfos (NullPointerException).
+            return true;
         }
         return false;
     }
diff --git a/media/base/android/media_player_bridge.cc b/media/base/android/media_player_bridge.cc
index deaba14..2f1fc0a 100644
--- a/media/base/android/media_player_bridge.cc
+++ b/media/base/android/media_player_bridge.cc
@@ -311,11 +311,13 @@
 }
 
 bool MediaPlayerBridge::HasVideo() const {
+  DCHECK(prepared_);
   JNIEnv* env = base::android::AttachCurrentThread();
   return Java_MediaPlayerBridge_hasVideo(env, j_media_player_bridge_.obj());
 }
 
 bool MediaPlayerBridge::HasAudio() const {
+  DCHECK(prepared_);
   JNIEnv* env = base::android::AttachCurrentThread();
   return Java_MediaPlayerBridge_hasAudio(env, j_media_player_bridge_.obj());
 }
diff --git a/media/blink/run_all_unittests.cc b/media/blink/run_all_unittests.cc
index b3a946d..bcbc4e3 100644
--- a/media/blink/run_all_unittests.cc
+++ b/media/blink/run_all_unittests.cc
@@ -70,8 +70,6 @@
  public:
   ~TestBlinkPlatformSupport() override;
 
-  const unsigned char* getTraceCategoryEnabledFlag(
-      const char* categoryName) override;
   blink::WebThread* currentThread() override { return &m_currentThread; }
 
  private:
@@ -80,12 +78,6 @@
 
 TestBlinkPlatformSupport::~TestBlinkPlatformSupport() {}
 
-const unsigned char* TestBlinkPlatformSupport::getTraceCategoryEnabledFlag(
-    const char* categoryName) {
-  static const unsigned char tracingIsDisabled = 0;
-  return &tracingIsDisabled;
-}
-
 class BlinkMediaTestSuite : public base::TestSuite {
  public:
   BlinkMediaTestSuite(int argc, char** argv);
diff --git a/printing/printing_context_win.cc b/printing/printing_context_win.cc
index 4eff7228..8a6dc17a 100644
--- a/printing/printing_context_win.cc
+++ b/printing/printing_context_win.cc
@@ -17,8 +17,8 @@
 #include "printing/printing_utils.h"
 #include "printing/units.h"
 #include "skia/ext/skia_utils_win.h"
-#include "ui/aura/remote_window_tree_host_win.h"
 #include "ui/aura/window.h"
+#include "ui/aura/window_tree_host.h"
 
 namespace printing {
 
diff --git a/testing/buildbot/chromium.win.json b/testing/buildbot/chromium.win.json
index 799df13f..fd775e3 100644
--- a/testing/buildbot/chromium.win.json
+++ b/testing/buildbot/chromium.win.json
@@ -348,12 +348,6 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
-        "test": "ash_unittests"
-      },
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "aura_unittests"
       },
       {
@@ -740,7 +734,6 @@
       "accessibility_unittests",
       "app_list_unittests",
       "app_shell_unittests",
-      "ash_unittests",
       "aura_unittests",
       "cacheinvalidation_unittests",
       "cast_unittests",
@@ -813,12 +806,6 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
-        "test": "ash_unittests"
-      },
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "aura_unittests"
       },
       {
@@ -1214,12 +1201,6 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
-        "test": "ash_unittests"
-      },
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "aura_unittests"
       },
       {
@@ -1559,7 +1540,6 @@
       "accessibility_unittests",
       "app_list_unittests",
       "app_shell_unittests",
-      "ash_unittests",
       "aura_unittests",
       "cacheinvalidation_unittests",
       "cast_unittests",
@@ -1670,7 +1650,6 @@
       "accessibility_unittests",
       "app_list_unittests",
       "app_shell_unittests",
-      "ash_unittests",
       "aura_unittests",
       "cacheinvalidation_unittests",
       "cast_unittests",
diff --git a/testing/libfuzzer/fuzzers/brotli_fuzzer.cc b/testing/libfuzzer/fuzzers/brotli_fuzzer.cc
index 9c45db4..41e5d350 100644
--- a/testing/libfuzzer/fuzzers/brotli_fuzzer.cc
+++ b/testing/libfuzzer/fuzzers/brotli_fuzzer.cc
@@ -8,20 +8,35 @@
 
 // Entry point for LibFuzzer.
 extern "C" int LLVMFuzzerTestOneInput(const unsigned char* data, size_t size) {
-  int kBufferSize = 1024;
+  size_t addend = 0;
+  if (size > 0)
+    addend = data[size - 1] & 7;
+  const uint8_t* next_in = data;
+
+  const int kBufferSize = 1024;
   uint8_t* buffer = new uint8_t[kBufferSize];
   BrotliState* state = new BrotliState();
   BrotliStateInit(state);
 
-  size_t avail_in = size;
-  const uint8_t* next_in = data;
-  BrotliResult result = BROTLI_RESULT_NEEDS_MORE_OUTPUT;
-  while (result == BROTLI_RESULT_NEEDS_MORE_OUTPUT) {
-    size_t avail_out = kBufferSize;
-    uint8_t* next_out = buffer;
-    size_t total_out;
-    result = BrotliDecompressStream(
-        &avail_in, &next_in, &avail_out, &next_out, &total_out, state);
+  if (addend == 0)
+    addend = size;
+  /* Test both fast (addend == size) and slow (addend <= 7) decoding paths. */
+  for (size_t i = 0; i < size;) {
+    size_t next_i = i + addend;
+    if (next_i > size)
+      next_i = size;
+    size_t avail_in = next_i - i;
+    i = next_i;
+    BrotliResult result = BROTLI_RESULT_NEEDS_MORE_OUTPUT;
+    while (result == BROTLI_RESULT_NEEDS_MORE_OUTPUT) {
+      size_t avail_out = kBufferSize;
+      uint8_t* next_out = buffer;
+      size_t total_out;
+      result = BrotliDecompressStream(
+          &avail_in, &next_in, &avail_out, &next_out, &total_out, state);
+    }
+    if (result != BROTLI_RESULT_NEEDS_MORE_INPUT)
+      break;
   }
 
   BrotliStateCleanup(state);
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations
index 3bc43ece..079eedce 100644
--- a/third_party/WebKit/LayoutTests/TestExpectations
+++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -254,6 +254,9 @@
 crbug.com/576589 fast/repaint/multi-layout-one-frame.html [ NeedsRebaseline ]
 crbug.com/576589 fast/repaint/subtree-root-skipped.html [ NeedsRebaseline ]
 crbug.com/576589 fast/text/international/mixed-directionality-selection.html [ NeedsRebaseline ]
+crbug.com/576589 [ Mac10.10 ] tables/mozilla/bugs/bug46368-1.html [ NeedsRebaseline ]
+crbug.com/576589 [ Mac10.10 ] tables/mozilla/bugs/bug46368-2.html [ NeedsRebaseline ]
+crbug.com/576589 [ Mac10.10 ] tables/mozilla/dom/tableDom.html [ NeedsRebaseline ]
 
 crbug.com/498539 http/tests/inspector/elements/styles/selector-line.html [ Pass Timeout ]
 crbug.com/498539 http/tests/inspector/network/network-datareceived.html [ Pass Timeout ]
@@ -365,6 +368,7 @@
 # SPv2 paint properties are still being implemented.
 crbug.com/537409 virtual/spv2/ [ Skip ]
 crbug.com/563667 virtual/spv2/fast/block/basic/001.html [ Pass ]
+crbug.com/563667 virtual/spv2/fast/block/positioning/static-distance-with-positioned-ancestor.html [ Pass ]
 
 # In imported/web-platform-tests/html/, we prefer checking in failure
 # expectation files. The following tests with [ Failure ] don't have failure
diff --git a/third_party/WebKit/LayoutTests/animations/interpolation/svg-d-interpolation-expected.txt b/third_party/WebKit/LayoutTests/animations/interpolation/svg-d-interpolation-expected.txt
new file mode 100644
index 0000000..4714f0e8
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/animations/interpolation/svg-d-interpolation-expected.txt
@@ -0,0 +1,553 @@
+This is a testharness.js-based test.
+PASS This test uses interpolation-test.js. 
+PASS CSS Transitions: property <d> from [path('m 0 0 h 1 h 2')] to [path('m 0 0 h 3')] at (-0.3) is [path('m 0 0 h 3')] 
+PASS CSS Transitions: property <d> from [path('m 0 0 h 1 h 2')] to [path('m 0 0 h 3')] at (0) is [path('m 0 0 h 3')] 
+PASS CSS Transitions: property <d> from [path('m 0 0 h 1 h 2')] to [path('m 0 0 h 3')] at (0.3) is [path('m 0 0 h 3')] 
+PASS CSS Transitions: property <d> from [path('m 0 0 h 1 h 2')] to [path('m 0 0 h 3')] at (0.5) is [path('m 0 0 h 3')] 
+PASS CSS Transitions: property <d> from [path('m 0 0 h 1 h 2')] to [path('m 0 0 h 3')] at (0.6) is [path('m 0 0 h 3')] 
+PASS CSS Transitions: property <d> from [path('m 0 0 h 1 h 2')] to [path('m 0 0 h 3')] at (1) is [path('m 0 0 h 3')] 
+PASS CSS Transitions: property <d> from [path('m 0 0 h 1 h 2')] to [path('m 0 0 h 3')] at (1.5) is [path('m 0 0 h 3')] 
+PASS CSS Transitions: property <d> from [path('m 10 0 h 1')] to [path('m 20 0 v 2')] at (-0.3) is [path('m 20 0 v 2')] 
+PASS CSS Transitions: property <d> from [path('m 10 0 h 1')] to [path('m 20 0 v 2')] at (0) is [path('m 20 0 v 2')] 
+PASS CSS Transitions: property <d> from [path('m 10 0 h 1')] to [path('m 20 0 v 2')] at (0.3) is [path('m 20 0 v 2')] 
+PASS CSS Transitions: property <d> from [path('m 10 0 h 1')] to [path('m 20 0 v 2')] at (0.5) is [path('m 20 0 v 2')] 
+PASS CSS Transitions: property <d> from [path('m 10 0 h 1')] to [path('m 20 0 v 2')] at (0.6) is [path('m 20 0 v 2')] 
+PASS CSS Transitions: property <d> from [path('m 10 0 h 1')] to [path('m 20 0 v 2')] at (1) is [path('m 20 0 v 2')] 
+PASS CSS Transitions: property <d> from [path('m 10 0 h 1')] to [path('m 20 0 v 2')] at (1.5) is [path('m 20 0 v 2')] 
+PASS CSS Transitions: property <d> from [path('m 1 2 l 3 4 Z')] to [path('m 1 2 l 3 4')] at (-0.3) is [path('m 1 2 l 3 4')] 
+PASS CSS Transitions: property <d> from [path('m 1 2 l 3 4 Z')] to [path('m 1 2 l 3 4')] at (0) is [path('m 1 2 l 3 4')] 
+PASS CSS Transitions: property <d> from [path('m 1 2 l 3 4 Z')] to [path('m 1 2 l 3 4')] at (0.3) is [path('m 1 2 l 3 4')] 
+PASS CSS Transitions: property <d> from [path('m 1 2 l 3 4 Z')] to [path('m 1 2 l 3 4')] at (0.5) is [path('m 1 2 l 3 4')] 
+PASS CSS Transitions: property <d> from [path('m 1 2 l 3 4 Z')] to [path('m 1 2 l 3 4')] at (0.6) is [path('m 1 2 l 3 4')] 
+PASS CSS Transitions: property <d> from [path('m 1 2 l 3 4 Z')] to [path('m 1 2 l 3 4')] at (1) is [path('m 1 2 l 3 4')] 
+PASS CSS Transitions: property <d> from [path('m 1 2 l 3 4 Z')] to [path('m 1 2 l 3 4')] at (1.5) is [path('m 1 2 l 3 4')] 
+PASS CSS Transitions: property <d> from [path('m 0 0 Z')] to [path('m 0 0 Z')] at (-0.4) is [path('m 0 0 Z')] 
+PASS CSS Transitions: property <d> from [path('m 0 0 Z')] to [path('m 0 0 Z')] at (0) is [path('m 0 0 Z')] 
+PASS CSS Transitions: property <d> from [path('m 0 0 Z')] to [path('m 0 0 Z')] at (0.2) is [path('m 0 0 Z')] 
+PASS CSS Transitions: property <d> from [path('m 0 0 Z')] to [path('m 0 0 Z')] at (0.6) is [path('m 0 0 Z')] 
+PASS CSS Transitions: property <d> from [path('m 0 0 Z')] to [path('m 0 0 Z')] at (1) is [path('m 0 0 Z')] 
+PASS CSS Transitions: property <d> from [path('m 0 0 Z')] to [path('m 0 0 Z')] at (1.4) is [path('m 0 0 Z')] 
+PASS CSS Transitions: property <d> from [path('M 20 50')] to [path('M 30 70')] at (-0.4) is [path('M 16 42')] 
+PASS CSS Transitions: property <d> from [path('M 20 50')] to [path('M 30 70')] at (0) is [path('M 20 50')] 
+PASS CSS Transitions: property <d> from [path('M 20 50')] to [path('M 30 70')] at (0.2) is [path('M 22 54')] 
+PASS CSS Transitions: property <d> from [path('M 20 50')] to [path('M 30 70')] at (0.6) is [path('M 26 62')] 
+PASS CSS Transitions: property <d> from [path('M 20 50')] to [path('M 30 70')] at (1) is [path('M 30 70')] 
+PASS CSS Transitions: property <d> from [path('M 20 50')] to [path('M 30 70')] at (1.4) is [path('M 34 78')] 
+PASS CSS Transitions: property <d> from [path('m 20 50')] to [path('m 30 70')] at (-0.4) is [path('m 16 42')] 
+PASS CSS Transitions: property <d> from [path('m 20 50')] to [path('m 30 70')] at (0) is [path('m 20 50')] 
+PASS CSS Transitions: property <d> from [path('m 20 50')] to [path('m 30 70')] at (0.2) is [path('m 22 54')] 
+PASS CSS Transitions: property <d> from [path('m 20 50')] to [path('m 30 70')] at (0.6) is [path('m 26 62')] 
+PASS CSS Transitions: property <d> from [path('m 20 50')] to [path('m 30 70')] at (1) is [path('m 30 70')] 
+PASS CSS Transitions: property <d> from [path('m 20 50')] to [path('m 30 70')] at (1.4) is [path('m 34 78')] 
+PASS CSS Transitions: property <d> from [path('m 0 0 L 20 50')] to [path('m 0 0 L 30 70')] at (-0.4) is [path('m 0 0 L 16 42')] 
+PASS CSS Transitions: property <d> from [path('m 0 0 L 20 50')] to [path('m 0 0 L 30 70')] at (0) is [path('m 0 0 L 20 50')] 
+PASS CSS Transitions: property <d> from [path('m 0 0 L 20 50')] to [path('m 0 0 L 30 70')] at (0.2) is [path('m 0 0 L 22 54')] 
+PASS CSS Transitions: property <d> from [path('m 0 0 L 20 50')] to [path('m 0 0 L 30 70')] at (0.6) is [path('m 0 0 L 26 62')] 
+PASS CSS Transitions: property <d> from [path('m 0 0 L 20 50')] to [path('m 0 0 L 30 70')] at (1) is [path('m 0 0 L 30 70')] 
+PASS CSS Transitions: property <d> from [path('m 0 0 L 20 50')] to [path('m 0 0 L 30 70')] at (1.4) is [path('m 0 0 L 34 78')] 
+PASS CSS Transitions: property <d> from [path('m 0 0 l 20 50')] to [path('m 0 0 l 30 70')] at (-0.4) is [path('m 0 0 l 16 42')] 
+PASS CSS Transitions: property <d> from [path('m 0 0 l 20 50')] to [path('m 0 0 l 30 70')] at (0) is [path('m 0 0 l 20 50')] 
+PASS CSS Transitions: property <d> from [path('m 0 0 l 20 50')] to [path('m 0 0 l 30 70')] at (0.2) is [path('m 0 0 l 22 54')] 
+PASS CSS Transitions: property <d> from [path('m 0 0 l 20 50')] to [path('m 0 0 l 30 70')] at (0.6) is [path('m 0 0 l 26 62')] 
+PASS CSS Transitions: property <d> from [path('m 0 0 l 20 50')] to [path('m 0 0 l 30 70')] at (1) is [path('m 0 0 l 30 70')] 
+PASS CSS Transitions: property <d> from [path('m 0 0 l 20 50')] to [path('m 0 0 l 30 70')] at (1.4) is [path('m 0 0 l 34 78')] 
+PASS CSS Transitions: property <d> from [path('m 0 0 C 32 42 52 62 12 22')] to [path('m 0 0 C 37 47 57 67 17 27')] at (-0.4) is [path('m 0 0 C 30 40 50 60 10 20')] 
+PASS CSS Transitions: property <d> from [path('m 0 0 C 32 42 52 62 12 22')] to [path('m 0 0 C 37 47 57 67 17 27')] at (0) is [path('m 0 0 C 32 42 52 62 12 22')] 
+PASS CSS Transitions: property <d> from [path('m 0 0 C 32 42 52 62 12 22')] to [path('m 0 0 C 37 47 57 67 17 27')] at (0.2) is [path('m 0 0 C 33 43 53 63 13 23')] 
+PASS CSS Transitions: property <d> from [path('m 0 0 C 32 42 52 62 12 22')] to [path('m 0 0 C 37 47 57 67 17 27')] at (0.6) is [path('m 0 0 C 35 45 55 65 15 25')] 
+PASS CSS Transitions: property <d> from [path('m 0 0 C 32 42 52 62 12 22')] to [path('m 0 0 C 37 47 57 67 17 27')] at (1) is [path('m 0 0 C 37 47 57 67 17 27')] 
+PASS CSS Transitions: property <d> from [path('m 0 0 C 32 42 52 62 12 22')] to [path('m 0 0 C 37 47 57 67 17 27')] at (1.4) is [path('m 0 0 C 39 49 59 69 19 29')] 
+PASS CSS Transitions: property <d> from [path('m 0 0 c 32 42 52 62 12 22')] to [path('m 0 0 c 37 47 57 67 17 27')] at (-0.4) is [path('m 0 0 c 30 40 50 60 10 20')] 
+PASS CSS Transitions: property <d> from [path('m 0 0 c 32 42 52 62 12 22')] to [path('m 0 0 c 37 47 57 67 17 27')] at (0) is [path('m 0 0 c 32 42 52 62 12 22')] 
+PASS CSS Transitions: property <d> from [path('m 0 0 c 32 42 52 62 12 22')] to [path('m 0 0 c 37 47 57 67 17 27')] at (0.2) is [path('m 0 0 c 33 43 53 63 13 23')] 
+PASS CSS Transitions: property <d> from [path('m 0 0 c 32 42 52 62 12 22')] to [path('m 0 0 c 37 47 57 67 17 27')] at (0.6) is [path('m 0 0 c 35 45 55 65 15 25')] 
+PASS CSS Transitions: property <d> from [path('m 0 0 c 32 42 52 62 12 22')] to [path('m 0 0 c 37 47 57 67 17 27')] at (1) is [path('m 0 0 c 37 47 57 67 17 27')] 
+PASS CSS Transitions: property <d> from [path('m 0 0 c 32 42 52 62 12 22')] to [path('m 0 0 c 37 47 57 67 17 27')] at (1.4) is [path('m 0 0 c 39 49 59 69 19 29')] 
+PASS CSS Transitions: property <d> from [path('m 0 0 Q 32 42 52 62')] to [path('m 0 0 Q 37 47 57 67')] at (-0.4) is [path('m 0 0 Q 30 40 50 60')] 
+PASS CSS Transitions: property <d> from [path('m 0 0 Q 32 42 52 62')] to [path('m 0 0 Q 37 47 57 67')] at (0) is [path('m 0 0 Q 32 42 52 62')] 
+PASS CSS Transitions: property <d> from [path('m 0 0 Q 32 42 52 62')] to [path('m 0 0 Q 37 47 57 67')] at (0.2) is [path('m 0 0 Q 33 43 53 63')] 
+PASS CSS Transitions: property <d> from [path('m 0 0 Q 32 42 52 62')] to [path('m 0 0 Q 37 47 57 67')] at (0.6) is [path('m 0 0 Q 35 45 55 65')] 
+PASS CSS Transitions: property <d> from [path('m 0 0 Q 32 42 52 62')] to [path('m 0 0 Q 37 47 57 67')] at (1) is [path('m 0 0 Q 37 47 57 67')] 
+PASS CSS Transitions: property <d> from [path('m 0 0 Q 32 42 52 62')] to [path('m 0 0 Q 37 47 57 67')] at (1.4) is [path('m 0 0 Q 39 49 59 69')] 
+PASS CSS Transitions: property <d> from [path('m 0 0 q 32 42 52 62')] to [path('m 0 0 q 37 47 57 67')] at (-0.4) is [path('m 0 0 q 30 40 50 60')] 
+PASS CSS Transitions: property <d> from [path('m 0 0 q 32 42 52 62')] to [path('m 0 0 q 37 47 57 67')] at (0) is [path('m 0 0 q 32 42 52 62')] 
+PASS CSS Transitions: property <d> from [path('m 0 0 q 32 42 52 62')] to [path('m 0 0 q 37 47 57 67')] at (0.2) is [path('m 0 0 q 33 43 53 63')] 
+PASS CSS Transitions: property <d> from [path('m 0 0 q 32 42 52 62')] to [path('m 0 0 q 37 47 57 67')] at (0.6) is [path('m 0 0 q 35 45 55 65')] 
+PASS CSS Transitions: property <d> from [path('m 0 0 q 32 42 52 62')] to [path('m 0 0 q 37 47 57 67')] at (1) is [path('m 0 0 q 37 47 57 67')] 
+PASS CSS Transitions: property <d> from [path('m 0 0 q 32 42 52 62')] to [path('m 0 0 q 37 47 57 67')] at (1.4) is [path('m 0 0 q 39 49 59 69')] 
+PASS CSS Transitions: property <d> from [path('m 0 0 A 10 20 30 1 0 40 50')] to [path('m 0 0 A 60 70 80 0 1 90 100')] at (-0.4) is [path('m 0 0 A -10 -2.98023e-7 10 1 0 20 30')] 
+PASS CSS Transitions: property <d> from [path('m 0 0 A 10 20 30 1 0 40 50')] to [path('m 0 0 A 60 70 80 0 1 90 100')] at (0) is [path('m 0 0 A 10 20 30 1 0 40 50')] 
+PASS CSS Transitions: property <d> from [path('m 0 0 A 10 20 30 1 0 40 50')] to [path('m 0 0 A 60 70 80 0 1 90 100')] at (0.2) is [path('m 0 0 A 20 30 40 1 0 50 60')] 
+PASS CSS Transitions: property <d> from [path('m 0 0 A 10 20 30 1 0 40 50')] to [path('m 0 0 A 60 70 80 0 1 90 100')] at (0.6) is [path('m 0 0 A 40 50 60 0 1 70 80')] 
+PASS CSS Transitions: property <d> from [path('m 0 0 A 10 20 30 1 0 40 50')] to [path('m 0 0 A 60 70 80 0 1 90 100')] at (1) is [path('m 0 0 A 60 70 80 0 1 90 100')] 
+PASS CSS Transitions: property <d> from [path('m 0 0 A 10 20 30 1 0 40 50')] to [path('m 0 0 A 60 70 80 0 1 90 100')] at (1.4) is [path('m 0 0 A 80 90 100 0 1 110 120')] 
+PASS CSS Transitions: property <d> from [path('m 0 0 a 10 20 30 1 0 40 50')] to [path('m 0 0 a 60 70 80 0 1 90 100')] at (-0.4) is [path('m 0 0 a -10 -2.98023e-7 10 1 0 20 30')] 
+PASS CSS Transitions: property <d> from [path('m 0 0 a 10 20 30 1 0 40 50')] to [path('m 0 0 a 60 70 80 0 1 90 100')] at (0) is [path('m 0 0 a 10 20 30 1 0 40 50')] 
+PASS CSS Transitions: property <d> from [path('m 0 0 a 10 20 30 1 0 40 50')] to [path('m 0 0 a 60 70 80 0 1 90 100')] at (0.2) is [path('m 0 0 a 20 30 40 1 0 50 60')] 
+PASS CSS Transitions: property <d> from [path('m 0 0 a 10 20 30 1 0 40 50')] to [path('m 0 0 a 60 70 80 0 1 90 100')] at (0.6) is [path('m 0 0 a 40 50 60 0 1 70 80')] 
+PASS CSS Transitions: property <d> from [path('m 0 0 a 10 20 30 1 0 40 50')] to [path('m 0 0 a 60 70 80 0 1 90 100')] at (1) is [path('m 0 0 a 60 70 80 0 1 90 100')] 
+PASS CSS Transitions: property <d> from [path('m 0 0 a 10 20 30 1 0 40 50')] to [path('m 0 0 a 60 70 80 0 1 90 100')] at (1.4) is [path('m 0 0 a 80 90 100 0 1 110 120')] 
+PASS CSS Transitions: property <d> from [path('m 0 0 H 10')] to [path('m 0 0 H 60')] at (-0.4) is [path('m 0 0 H -10')] 
+PASS CSS Transitions: property <d> from [path('m 0 0 H 10')] to [path('m 0 0 H 60')] at (0) is [path('m 0 0 H 10')] 
+PASS CSS Transitions: property <d> from [path('m 0 0 H 10')] to [path('m 0 0 H 60')] at (0.2) is [path('m 0 0 H 20')] 
+PASS CSS Transitions: property <d> from [path('m 0 0 H 10')] to [path('m 0 0 H 60')] at (0.6) is [path('m 0 0 H 40')] 
+PASS CSS Transitions: property <d> from [path('m 0 0 H 10')] to [path('m 0 0 H 60')] at (1) is [path('m 0 0 H 60')] 
+PASS CSS Transitions: property <d> from [path('m 0 0 H 10')] to [path('m 0 0 H 60')] at (1.4) is [path('m 0 0 H 80')] 
+PASS CSS Transitions: property <d> from [path('m 0 0 h 10')] to [path('m 0 0 h 60')] at (-0.4) is [path('m 0 0 h -10')] 
+PASS CSS Transitions: property <d> from [path('m 0 0 h 10')] to [path('m 0 0 h 60')] at (0) is [path('m 0 0 h 10')] 
+PASS CSS Transitions: property <d> from [path('m 0 0 h 10')] to [path('m 0 0 h 60')] at (0.2) is [path('m 0 0 h 20')] 
+PASS CSS Transitions: property <d> from [path('m 0 0 h 10')] to [path('m 0 0 h 60')] at (0.6) is [path('m 0 0 h 40')] 
+PASS CSS Transitions: property <d> from [path('m 0 0 h 10')] to [path('m 0 0 h 60')] at (1) is [path('m 0 0 h 60')] 
+PASS CSS Transitions: property <d> from [path('m 0 0 h 10')] to [path('m 0 0 h 60')] at (1.4) is [path('m 0 0 h 80')] 
+PASS CSS Transitions: property <d> from [path('m 0 0 V 10')] to [path('m 0 0 V 60')] at (-0.4) is [path('m 0 0 V -10')] 
+PASS CSS Transitions: property <d> from [path('m 0 0 V 10')] to [path('m 0 0 V 60')] at (0) is [path('m 0 0 V 10')] 
+PASS CSS Transitions: property <d> from [path('m 0 0 V 10')] to [path('m 0 0 V 60')] at (0.2) is [path('m 0 0 V 20')] 
+PASS CSS Transitions: property <d> from [path('m 0 0 V 10')] to [path('m 0 0 V 60')] at (0.6) is [path('m 0 0 V 40')] 
+PASS CSS Transitions: property <d> from [path('m 0 0 V 10')] to [path('m 0 0 V 60')] at (1) is [path('m 0 0 V 60')] 
+PASS CSS Transitions: property <d> from [path('m 0 0 V 10')] to [path('m 0 0 V 60')] at (1.4) is [path('m 0 0 V 80')] 
+PASS CSS Transitions: property <d> from [path('m 0 0 v 10')] to [path('m 0 0 v 60')] at (-0.4) is [path('m 0 0 v -10')] 
+PASS CSS Transitions: property <d> from [path('m 0 0 v 10')] to [path('m 0 0 v 60')] at (0) is [path('m 0 0 v 10')] 
+PASS CSS Transitions: property <d> from [path('m 0 0 v 10')] to [path('m 0 0 v 60')] at (0.2) is [path('m 0 0 v 20')] 
+PASS CSS Transitions: property <d> from [path('m 0 0 v 10')] to [path('m 0 0 v 60')] at (0.6) is [path('m 0 0 v 40')] 
+PASS CSS Transitions: property <d> from [path('m 0 0 v 10')] to [path('m 0 0 v 60')] at (1) is [path('m 0 0 v 60')] 
+PASS CSS Transitions: property <d> from [path('m 0 0 v 10')] to [path('m 0 0 v 60')] at (1.4) is [path('m 0 0 v 80')] 
+PASS CSS Transitions: property <d> from [path('m 0 0 S 32 42 52 62')] to [path('m 0 0 S 37 47 57 67')] at (-0.4) is [path('m 0 0 S 30 40 50 60')] 
+PASS CSS Transitions: property <d> from [path('m 0 0 S 32 42 52 62')] to [path('m 0 0 S 37 47 57 67')] at (0) is [path('m 0 0 S 32 42 52 62')] 
+PASS CSS Transitions: property <d> from [path('m 0 0 S 32 42 52 62')] to [path('m 0 0 S 37 47 57 67')] at (0.2) is [path('m 0 0 S 33 43 53 63')] 
+PASS CSS Transitions: property <d> from [path('m 0 0 S 32 42 52 62')] to [path('m 0 0 S 37 47 57 67')] at (0.6) is [path('m 0 0 S 35 45 55 65')] 
+PASS CSS Transitions: property <d> from [path('m 0 0 S 32 42 52 62')] to [path('m 0 0 S 37 47 57 67')] at (1) is [path('m 0 0 S 37 47 57 67')] 
+PASS CSS Transitions: property <d> from [path('m 0 0 S 32 42 52 62')] to [path('m 0 0 S 37 47 57 67')] at (1.4) is [path('m 0 0 S 39 49 59 69')] 
+PASS CSS Transitions: property <d> from [path('m 0 0 s 32 42 52 62')] to [path('m 0 0 s 37 47 57 67')] at (-0.4) is [path('m 0 0 s 30 40 50 60')] 
+PASS CSS Transitions: property <d> from [path('m 0 0 s 32 42 52 62')] to [path('m 0 0 s 37 47 57 67')] at (0) is [path('m 0 0 s 32 42 52 62')] 
+PASS CSS Transitions: property <d> from [path('m 0 0 s 32 42 52 62')] to [path('m 0 0 s 37 47 57 67')] at (0.2) is [path('m 0 0 s 33 43 53 63')] 
+PASS CSS Transitions: property <d> from [path('m 0 0 s 32 42 52 62')] to [path('m 0 0 s 37 47 57 67')] at (0.6) is [path('m 0 0 s 35 45 55 65')] 
+PASS CSS Transitions: property <d> from [path('m 0 0 s 32 42 52 62')] to [path('m 0 0 s 37 47 57 67')] at (1) is [path('m 0 0 s 37 47 57 67')] 
+PASS CSS Transitions: property <d> from [path('m 0 0 s 32 42 52 62')] to [path('m 0 0 s 37 47 57 67')] at (1.4) is [path('m 0 0 s 39 49 59 69')] 
+PASS CSS Transitions: property <d> from [path('m 0 0 T 20 50')] to [path('m 0 0 T 30 70')] at (-0.4) is [path('m 0 0 T 16 42')] 
+PASS CSS Transitions: property <d> from [path('m 0 0 T 20 50')] to [path('m 0 0 T 30 70')] at (0) is [path('m 0 0 T 20 50')] 
+PASS CSS Transitions: property <d> from [path('m 0 0 T 20 50')] to [path('m 0 0 T 30 70')] at (0.2) is [path('m 0 0 T 22 54')] 
+PASS CSS Transitions: property <d> from [path('m 0 0 T 20 50')] to [path('m 0 0 T 30 70')] at (0.6) is [path('m 0 0 T 26 62')] 
+PASS CSS Transitions: property <d> from [path('m 0 0 T 20 50')] to [path('m 0 0 T 30 70')] at (1) is [path('m 0 0 T 30 70')] 
+PASS CSS Transitions: property <d> from [path('m 0 0 T 20 50')] to [path('m 0 0 T 30 70')] at (1.4) is [path('m 0 0 T 34 78')] 
+PASS CSS Transitions: property <d> from [path('m 0 0 t 20 50')] to [path('m 0 0 t 30 70')] at (-0.4) is [path('m 0 0 t 16 42')] 
+PASS CSS Transitions: property <d> from [path('m 0 0 t 20 50')] to [path('m 0 0 t 30 70')] at (0) is [path('m 0 0 t 20 50')] 
+PASS CSS Transitions: property <d> from [path('m 0 0 t 20 50')] to [path('m 0 0 t 30 70')] at (0.2) is [path('m 0 0 t 22 54')] 
+PASS CSS Transitions: property <d> from [path('m 0 0 t 20 50')] to [path('m 0 0 t 30 70')] at (0.6) is [path('m 0 0 t 26 62')] 
+PASS CSS Transitions: property <d> from [path('m 0 0 t 20 50')] to [path('m 0 0 t 30 70')] at (1) is [path('m 0 0 t 30 70')] 
+PASS CSS Transitions: property <d> from [path('m 0 0 t 20 50')] to [path('m 0 0 t 30 70')] at (1.4) is [path('m 0 0 t 34 78')] 
+FAIL CSS Transitions: property <d> from [path('M 0 0 L 100 100 M 100 200 L 200 200 Z L 200 100 Z')] to [path('M 0 0 L 100 100 m 0 100 l 100 0 z l 200 100 z')] at (-0.4) is [path('M 0 0 L 100 100 M 100 200 L 200 200 Z L 120 20 Z')] assert_equals: expected "path ( ' M 0 0 L 100 100 m 0 100 l 100 0 Z l 60 - 180 Z ' ) " but got "path ( ' M 0 0 L 100 100 M 100 200 L 200 200 Z L 120 20 Z ' ) "
+PASS CSS Transitions: property <d> from [path('M 0 0 L 100 100 M 100 200 L 200 200 Z L 200 100 Z')] to [path('M 0 0 L 100 100 m 0 100 l 100 0 z l 200 100 z')] at (0) is [path('M 0 0 L 100 100 M 100 200 L 200 200 Z L 200 100 Z')] 
+FAIL CSS Transitions: property <d> from [path('M 0 0 L 100 100 M 100 200 L 200 200 Z L 200 100 Z')] to [path('M 0 0 L 100 100 m 0 100 l 100 0 z l 200 100 z')] at (0.2) is [path('M 0 0 L 100 100 M 100 200 L 200 200 Z L 240 140 Z')] assert_equals: expected "path ( ' M 0 0 L 100 100 m 0 100 l 100 0 Z l 120 - 60 Z ' ) " but got "path ( ' M 0 0 L 100 100 M 100 200 L 200 200 Z L 240 140 Z ' ) "
+FAIL CSS Transitions: property <d> from [path('M 0 0 L 100 100 M 100 200 L 200 200 Z L 200 100 Z')] to [path('M 0 0 L 100 100 m 0 100 l 100 0 z l 200 100 z')] at (0.6) is [path('M 0 0 L 100 100 m 0 100 l 100 0 Z l 120 20 Z')] assert_equals: expected "path ( ' M 0 0 L 100 100 m 0 100 l 100 0 Z l 160 20 Z ' ) " but got "path ( ' M 0 0 L 100 100 m 0 100 l 100 0 Z l 120 20 Z ' ) "
+PASS CSS Transitions: property <d> from [path('M 0 0 L 100 100 M 100 200 L 200 200 Z L 200 100 Z')] to [path('M 0 0 L 100 100 m 0 100 l 100 0 z l 200 100 z')] at (1) is [path('M 0 0 L 100 100 m 0 100 l 100 0 Z l 200 100 Z')] 
+FAIL CSS Transitions: property <d> from [path('M 0 0 L 100 100 M 100 200 L 200 200 Z L 200 100 Z')] to [path('M 0 0 L 100 100 m 0 100 l 100 0 z l 200 100 z')] at (1.4) is [path('M 0 0 L 100 100 m 0 100 l 100 0 Z l 280 180 Z')] assert_equals: expected "path ( ' M 0 0 L 100 100 m 0 100 l 100 0 Z l 240 180 Z ' ) " but got "path ( ' M 0 0 L 100 100 m 0 100 l 100 0 Z l 280 180 Z ' ) "
+FAIL CSS Transitions: property <d> from [path('M 0 0 L 100 100 M 100 200 L 200 200 Z L 200 100 Z')] to [path('M 0 0 L 100 100 m 0 100 l 100 0 z l 100 -100 z')] at (-0.4) is [path('M 0 0 L 100 100 M 100 200 L 200 200 Z L 160 100 Z')] assert_equals: expected "path ( ' M 0 0 L 100 100 m 0 100 l 100 0 Z l 100 - 100 Z ' ) " but got "path ( ' M 0 0 L 100 100 M 100 200 L 200 200 Z L 160 100 Z ' ) "
+PASS CSS Transitions: property <d> from [path('M 0 0 L 100 100 M 100 200 L 200 200 Z L 200 100 Z')] to [path('M 0 0 L 100 100 m 0 100 l 100 0 z l 100 -100 z')] at (0) is [path('M 0 0 L 100 100 M 100 200 L 200 200 Z L 200 100 Z')] 
+FAIL CSS Transitions: property <d> from [path('M 0 0 L 100 100 M 100 200 L 200 200 Z L 200 100 Z')] to [path('M 0 0 L 100 100 m 0 100 l 100 0 z l 100 -100 z')] at (0.2) is [path('M 0 0 L 100 100 M 100 200 L 200 200 Z L 220 100 Z')] assert_equals: expected "path ( ' M 0 0 L 100 100 m 0 100 l 100 0 Z l 100 - 100 Z ' ) " but got "path ( ' M 0 0 L 100 100 M 100 200 L 200 200 Z L 220 100 Z ' ) "
+FAIL CSS Transitions: property <d> from [path('M 0 0 L 100 100 M 100 200 L 200 200 Z L 200 100 Z')] to [path('M 0 0 L 100 100 m 0 100 l 100 0 z l 100 -100 z')] at (0.6) is [path('M 0 0 L 100 100 m 0 100 l 100 0 Z l 60 -100 Z')] assert_equals: expected "path ( ' M 0 0 L 100 100 m 0 100 l 100 0 Z l 100 - 100 Z ' ) " but got "path ( ' M 0 0 L 100 100 m 0 100 l 100 0 Z l 60 - 100 Z ' ) "
+PASS CSS Transitions: property <d> from [path('M 0 0 L 100 100 M 100 200 L 200 200 Z L 200 100 Z')] to [path('M 0 0 L 100 100 m 0 100 l 100 0 z l 100 -100 z')] at (1) is [path('M 0 0 L 100 100 m 0 100 l 100 0 Z l 100 -100 Z')] 
+FAIL CSS Transitions: property <d> from [path('M 0 0 L 100 100 M 100 200 L 200 200 Z L 200 100 Z')] to [path('M 0 0 L 100 100 m 0 100 l 100 0 z l 100 -100 z')] at (1.4) is [path('M 0 0 L 100 100 m 0 100 l 100 0 Z l 140 -100 Z')] assert_equals: expected "path ( ' M 0 0 L 100 100 m 0 100 l 100 0 Z l 100 - 100 Z ' ) " but got "path ( ' M 0 0 L 100 100 m 0 100 l 100 0 Z l 140 - 100 Z ' ) "
+FAIL CSS Transitions: property <d> from [path('m 10 20 l 20 30 z l 50 60 z m 70 80 l 90 60 z t 70 120')] to [path('M 110 120 L 130 150 Z L 80 110 Z M 100 140 L 190 200 Z T 210 220')] at (-0.4) is [path('m -30 -20 l 20 30 Z l 90 100 Z m 90 100 l 90 60 Z t 90 160')] assert_equals: expected "path ( ' M - 30 - 20 L - 10 10 Z L 52 68 Z M 72 84 L 162 144 Z T 126 220 ' ) " but got "path ( ' m - 30 - 20 l 20 30 Z l 90 100 Z m 90 100 l 90 60 Z t 90 160 ' ) "
+PASS CSS Transitions: property <d> from [path('m 10 20 l 20 30 z l 50 60 z m 70 80 l 90 60 z t 70 120')] to [path('M 110 120 L 130 150 Z L 80 110 Z M 100 140 L 190 200 Z T 210 220')] at (0) is [path('m 10 20 l 20 30 Z l 50 60 Z m 70 80 l 90 60 Z t 70 120')] 
+FAIL CSS Transitions: property <d> from [path('m 10 20 l 20 30 z l 50 60 z m 70 80 l 90 60 z t 70 120')] to [path('M 110 120 L 130 150 Z L 80 110 Z M 100 140 L 190 200 Z T 210 220')] at (0.2) is [path('m 30 40 l 20 30 Z l 30 40 Z m 60 70 l 90 60 Z t 60 100')] assert_equals: expected "path ( ' M 30 40 L 50 70 Z L 64 86 Z M 84 108 L 174 168 Z T 162 220 ' ) " but got "path ( ' m 30 40 l 20 30 Z l 30 40 Z m 60 70 l 90 60 Z t 60 100 ' ) "
+FAIL CSS Transitions: property <d> from [path('m 10 20 l 20 30 z l 50 60 z m 70 80 l 90 60 z t 70 120')] to [path('M 110 120 L 130 150 Z L 80 110 Z M 100 140 L 190 200 Z T 210 220')] at (0.6) is [path('M 70 80 L 90 110 Z L 80 110 Z M 120 160 L 210 220 Z T 250 280')] assert_equals: expected "path ( ' M 70 80 L 90 110 Z L 72 98 Z M 92 124 L 182 184 Z T 186 220 ' ) " but got "path ( ' M 70 80 L 90 110 Z L 80 110 Z M 120 160 L 210 220 Z T 250 280 ' ) "
+PASS CSS Transitions: property <d> from [path('m 10 20 l 20 30 z l 50 60 z m 70 80 l 90 60 z t 70 120')] to [path('M 110 120 L 130 150 Z L 80 110 Z M 100 140 L 190 200 Z T 210 220')] at (1) is [path('M 110 120 L 130 150 Z L 80 110 Z M 100 140 L 190 200 Z T 210 220')] 
+FAIL CSS Transitions: property <d> from [path('m 10 20 l 20 30 z l 50 60 z m 70 80 l 90 60 z t 70 120')] to [path('M 110 120 L 130 150 Z L 80 110 Z M 100 140 L 190 200 Z T 210 220')] at (1.4) is [path('M 150 160 L 170 190 Z L 80 110 Z M 80 120 L 170 180 Z T 170 160')] assert_equals: expected "path ( ' M 150 160 L 170 190 Z L 88 122 Z M 108 156 L 198 216 Z T 234 220 ' ) " but got "path ( ' M 150 160 L 170 190 Z L 80 110 Z M 80 120 L 170 180 Z T 170 160 ' ) "
+FAIL CSS Transitions: property <d> from [path('m 10 20 c 40 50 30 60 80 70 c 90 100 140 110 120 130')] to [path('M 110 120 C 140 150 130 160 180 170 C 290 300 340 310 320 330')] at (-0.4) is [path('m -30 -20 c 44 58 34 68 84 78 c 82 88 132 98 112 118')] assert_equals: expected "path ( ' M - 30 - 20 C 14 38 4 48 54 58 C 136 146 186 156 166 176 ' ) " but got "path ( ' m - 30 - 20 c 44 58 34 68 84 78 c 82 88 132 98 112 118 ' ) "
+PASS CSS Transitions: property <d> from [path('m 10 20 c 40 50 30 60 80 70 c 90 100 140 110 120 130')] to [path('M 110 120 C 140 150 130 160 180 170 C 290 300 340 310 320 330')] at (0) is [path('m 10 20 c 40 50 30 60 80 70 c 90 100 140 110 120 130')] 
+FAIL CSS Transitions: property <d> from [path('m 10 20 c 40 50 30 60 80 70 c 90 100 140 110 120 130')] to [path('M 110 120 C 140 150 130 160 180 170 C 290 300 340 310 320 330')] at (0.2) is [path('m 30 40 c 38 46 28 56 78 66 c 94 106 144 116 124 136')] assert_equals: expected "path ( ' M 30 40 C 68 86 58 96 108 106 C 202 212 252 222 232 242 ' ) " but got "path ( ' m 30 40 c 38 46 28 56 78 66 c 94 106 144 116 124 136 ' ) "
+PASS CSS Transitions: property <d> from [path('m 10 20 c 40 50 30 60 80 70 c 90 100 140 110 120 130')] to [path('M 110 120 C 140 150 130 160 180 170 C 290 300 340 310 320 330')] at (0.6) is [path('M 70 80 C 104 118 94 128 144 138 C 246 256 296 266 276 286')] 
+PASS CSS Transitions: property <d> from [path('m 10 20 c 40 50 30 60 80 70 c 90 100 140 110 120 130')] to [path('M 110 120 C 140 150 130 160 180 170 C 290 300 340 310 320 330')] at (1) is [path('M 110 120 C 140 150 130 160 180 170 C 290 300 340 310 320 330')] 
+PASS CSS Transitions: property <d> from [path('m 10 20 c 40 50 30 60 80 70 c 90 100 140 110 120 130')] to [path('M 110 120 C 140 150 130 160 180 170 C 290 300 340 310 320 330')] at (1.4) is [path('M 150 160 C 176 182 166 192 216 202 C 334 344 384 354 364 374')] 
+FAIL CSS Transitions: property <d> from [path('m 10 20 q 30 60 40 50 q 100 70 90 80')] to [path('M 110 120 Q 130 160 140 150 Q 200 170 190 180')] at (-0.4) is [path('m -30 -20 q 34 68 44 58 q 116 90 106 100')] assert_equals: expected "path ( ' M - 30 - 20 Q 4 48 14 38 Q 130 128 120 138 ' ) " but got "path ( ' m - 30 - 20 q 34 68 44 58 q 116 90 106 100 ' ) "
+PASS CSS Transitions: property <d> from [path('m 10 20 q 30 60 40 50 q 100 70 90 80')] to [path('M 110 120 Q 130 160 140 150 Q 200 170 190 180')] at (0) is [path('m 10 20 q 30 60 40 50 q 100 70 90 80')] 
+FAIL CSS Transitions: property <d> from [path('m 10 20 q 30 60 40 50 q 100 70 90 80')] to [path('M 110 120 Q 130 160 140 150 Q 200 170 190 180')] at (0.2) is [path('m 30 40 q 28 56 38 46 q 92 60 82 70')] assert_equals: expected "path ( ' M 30 40 Q 58 96 68 86 Q 160 146 150 156 ' ) " but got "path ( ' m 30 40 q 28 56 38 46 q 92 60 82 70 ' ) "
+PASS CSS Transitions: property <d> from [path('m 10 20 q 30 60 40 50 q 100 70 90 80')] to [path('M 110 120 Q 130 160 140 150 Q 200 170 190 180')] at (0.6) is [path('M 70 80 Q 94 128 104 118 Q 180 158 170 168')] 
+PASS CSS Transitions: property <d> from [path('m 10 20 q 30 60 40 50 q 100 70 90 80')] to [path('M 110 120 Q 130 160 140 150 Q 200 170 190 180')] at (1) is [path('M 110 120 Q 130 160 140 150 Q 200 170 190 180')] 
+PASS CSS Transitions: property <d> from [path('m 10 20 q 30 60 40 50 q 100 70 90 80')] to [path('M 110 120 Q 130 160 140 150 Q 200 170 190 180')] at (1.4) is [path('M 150 160 Q 166 192 176 182 Q 220 182 210 192')] 
+FAIL CSS Transitions: property <d> from [path('m 10 20 s 30 60 40 50 s 100 70 90 80')] to [path('M 110 120 S 130 160 140 150 S 200 170 190 180')] at (-0.4) is [path('m -30 -20 s 34 68 44 58 s 116 90 106 100')] assert_equals: expected "path ( ' M - 30 - 20 S 4 48 14 38 S 130 128 120 138 ' ) " but got "path ( ' m - 30 - 20 s 34 68 44 58 s 116 90 106 100 ' ) "
+PASS CSS Transitions: property <d> from [path('m 10 20 s 30 60 40 50 s 100 70 90 80')] to [path('M 110 120 S 130 160 140 150 S 200 170 190 180')] at (0) is [path('m 10 20 s 30 60 40 50 s 100 70 90 80')] 
+FAIL CSS Transitions: property <d> from [path('m 10 20 s 30 60 40 50 s 100 70 90 80')] to [path('M 110 120 S 130 160 140 150 S 200 170 190 180')] at (0.2) is [path('m 30 40 s 28 56 38 46 s 92 60 82 70')] assert_equals: expected "path ( ' M 30 40 S 58 96 68 86 S 160 146 150 156 ' ) " but got "path ( ' m 30 40 s 28 56 38 46 s 92 60 82 70 ' ) "
+PASS CSS Transitions: property <d> from [path('m 10 20 s 30 60 40 50 s 100 70 90 80')] to [path('M 110 120 S 130 160 140 150 S 200 170 190 180')] at (0.6) is [path('M 70 80 S 94 128 104 118 S 180 158 170 168')] 
+PASS CSS Transitions: property <d> from [path('m 10 20 s 30 60 40 50 s 100 70 90 80')] to [path('M 110 120 S 130 160 140 150 S 200 170 190 180')] at (1) is [path('M 110 120 S 130 160 140 150 S 200 170 190 180')] 
+PASS CSS Transitions: property <d> from [path('m 10 20 s 30 60 40 50 s 100 70 90 80')] to [path('M 110 120 S 130 160 140 150 S 200 170 190 180')] at (1.4) is [path('M 150 160 S 166 192 176 182 S 220 182 210 192')] 
+FAIL CSS Transitions: property <d> from [path('m 10 20 h 30 v 40 h 50 v 60 l 70 80')] to [path('M 110 120 H 130 V 140 H 250 V 260 L 270 280')] at (-0.4) is [path('m -30 -20 h 34 v 48 h 22 v 36 l 90 104')] assert_equals: expected "path ( ' M - 30 - 20 H 4 V 28 H 26 V 64 L 116 168 ' ) " but got "path ( ' m - 30 - 20 h 34 v 48 h 22 v 36 l 90 104 ' ) "
+PASS CSS Transitions: property <d> from [path('m 10 20 h 30 v 40 h 50 v 60 l 70 80')] to [path('M 110 120 H 130 V 140 H 250 V 260 L 270 280')] at (0) is [path('m 10 20 h 30 v 40 h 50 v 60 l 70 80')] 
+FAIL CSS Transitions: property <d> from [path('m 10 20 h 30 v 40 h 50 v 60 l 70 80')] to [path('M 110 120 H 130 V 140 H 250 V 260 L 270 280')] at (0.2) is [path('m 30 40 h 28 v 36 h 64 v 72 l 60 68')] assert_equals: expected "path ( ' M 30 40 H 58 V 76 H 122 V 148 L 182 216 ' ) " but got "path ( ' m 30 40 h 28 v 36 h 64 v 72 l 60 68 ' ) "
+PASS CSS Transitions: property <d> from [path('m 10 20 h 30 v 40 h 50 v 60 l 70 80')] to [path('M 110 120 H 130 V 140 H 250 V 260 L 270 280')] at (0.6) is [path('M 70 80 H 94 V 108 H 186 V 204 L 226 248')] 
+PASS CSS Transitions: property <d> from [path('m 10 20 h 30 v 40 h 50 v 60 l 70 80')] to [path('M 110 120 H 130 V 140 H 250 V 260 L 270 280')] at (1) is [path('M 110 120 H 130 V 140 H 250 V 260 L 270 280')] 
+PASS CSS Transitions: property <d> from [path('m 10 20 h 30 v 40 h 50 v 60 l 70 80')] to [path('M 110 120 H 130 V 140 H 250 V 260 L 270 280')] at (1.4) is [path('M 150 160 H 166 V 172 H 314 V 316 L 314 312')] 
+FAIL CSS Transitions: property <d> from [path('m 10 20 a 10 20 30 1 0 40 50 a 110 120 30 1 1 140 50')] to [path('M 20 30 A 60 70 80 0 1 90 100 A 160 170 80 0 1 90 100')] at (-0.4) is [path('m 6 16 a -10 -2.98023e-7 10 1 0 28 42 a 90 100 10 1 1 196 70')] assert_equals: expected "path ( ' M 6 16 A - 10 0 10 1 0 34 58 A 90 100 10 1 1 230 128 ' ) " but got "path ( ' m 6 16 a - 10 0 10 1 0 28 42 a 90 100 10 1 1 196 70 ' ) "
+PASS CSS Transitions: property <d> from [path('m 10 20 a 10 20 30 1 0 40 50 a 110 120 30 1 1 140 50')] to [path('M 20 30 A 60 70 80 0 1 90 100 A 160 170 80 0 1 90 100')] at (0) is [path('m 10 20 a 10 20 30 1 0 40 50 a 110 120 30 1 1 140 50')] 
+FAIL CSS Transitions: property <d> from [path('m 10 20 a 10 20 30 1 0 40 50 a 110 120 30 1 1 140 50')] to [path('M 20 30 A 60 70 80 0 1 90 100 A 160 170 80 0 1 90 100')] at (0.2) is [path('m 12 22 a 20 30 40 1 0 46 54 a 120 130 40 1 1 112 40')] assert_equals: expected "path ( ' M 12 22 A 20 30 40 1 0 58 76 A 120 130 40 1 1 170 116 ' ) " but got "path ( ' m 12 22 a 20 30 40 1 0 46 54 a 120 130 40 1 1 112 40 ' ) "
+PASS CSS Transitions: property <d> from [path('m 10 20 a 10 20 30 1 0 40 50 a 110 120 30 1 1 140 50')] to [path('M 20 30 A 60 70 80 0 1 90 100 A 160 170 80 0 1 90 100')] at (0.6) is [path('M 16 26 A 40 50 60 0 1 74 88 A 140 150 60 0 1 130 108')] 
+PASS CSS Transitions: property <d> from [path('m 10 20 a 10 20 30 1 0 40 50 a 110 120 30 1 1 140 50')] to [path('M 20 30 A 60 70 80 0 1 90 100 A 160 170 80 0 1 90 100')] at (1) is [path('M 20 30 A 60 70 80 0 1 90 100 A 160 170 80 0 1 90 100')] 
+PASS CSS Transitions: property <d> from [path('m 10 20 a 10 20 30 1 0 40 50 a 110 120 30 1 1 140 50')] to [path('M 20 30 A 60 70 80 0 1 90 100 A 160 170 80 0 1 90 100')] at (1.4) is [path('M 24 34 A 80 90 100 0 1 106 112 A 180 190 100 0 1 50 92')] 
+PASS CSS Animations: property <d> from [path('m 0 0 h 1 h 2')] to [path('m 0 0 h 3')] at (-0.3) is [path('m 0 0 h 1 h 2')] 
+PASS CSS Animations: property <d> from [path('m 0 0 h 1 h 2')] to [path('m 0 0 h 3')] at (0) is [path('m 0 0 h 1 h 2')] 
+PASS CSS Animations: property <d> from [path('m 0 0 h 1 h 2')] to [path('m 0 0 h 3')] at (0.3) is [path('m 0 0 h 1 h 2')] 
+PASS CSS Animations: property <d> from [path('m 0 0 h 1 h 2')] to [path('m 0 0 h 3')] at (0.5) is [path('m 0 0 h 3')] 
+PASS CSS Animations: property <d> from [path('m 0 0 h 1 h 2')] to [path('m 0 0 h 3')] at (0.6) is [path('m 0 0 h 3')] 
+PASS CSS Animations: property <d> from [path('m 0 0 h 1 h 2')] to [path('m 0 0 h 3')] at (1) is [path('m 0 0 h 3')] 
+PASS CSS Animations: property <d> from [path('m 0 0 h 1 h 2')] to [path('m 0 0 h 3')] at (1.5) is [path('m 0 0 h 3')] 
+PASS CSS Animations: property <d> from [path('m 10 0 h 1')] to [path('m 20 0 v 2')] at (-0.3) is [path('m 10 0 h 1')] 
+PASS CSS Animations: property <d> from [path('m 10 0 h 1')] to [path('m 20 0 v 2')] at (0) is [path('m 10 0 h 1')] 
+PASS CSS Animations: property <d> from [path('m 10 0 h 1')] to [path('m 20 0 v 2')] at (0.3) is [path('m 10 0 h 1')] 
+PASS CSS Animations: property <d> from [path('m 10 0 h 1')] to [path('m 20 0 v 2')] at (0.5) is [path('m 20 0 v 2')] 
+PASS CSS Animations: property <d> from [path('m 10 0 h 1')] to [path('m 20 0 v 2')] at (0.6) is [path('m 20 0 v 2')] 
+PASS CSS Animations: property <d> from [path('m 10 0 h 1')] to [path('m 20 0 v 2')] at (1) is [path('m 20 0 v 2')] 
+PASS CSS Animations: property <d> from [path('m 10 0 h 1')] to [path('m 20 0 v 2')] at (1.5) is [path('m 20 0 v 2')] 
+PASS CSS Animations: property <d> from [path('m 1 2 l 3 4 Z')] to [path('m 1 2 l 3 4')] at (-0.3) is [path('m 1 2 l 3 4 Z')] 
+PASS CSS Animations: property <d> from [path('m 1 2 l 3 4 Z')] to [path('m 1 2 l 3 4')] at (0) is [path('m 1 2 l 3 4 Z')] 
+PASS CSS Animations: property <d> from [path('m 1 2 l 3 4 Z')] to [path('m 1 2 l 3 4')] at (0.3) is [path('m 1 2 l 3 4 Z')] 
+PASS CSS Animations: property <d> from [path('m 1 2 l 3 4 Z')] to [path('m 1 2 l 3 4')] at (0.5) is [path('m 1 2 l 3 4')] 
+PASS CSS Animations: property <d> from [path('m 1 2 l 3 4 Z')] to [path('m 1 2 l 3 4')] at (0.6) is [path('m 1 2 l 3 4')] 
+PASS CSS Animations: property <d> from [path('m 1 2 l 3 4 Z')] to [path('m 1 2 l 3 4')] at (1) is [path('m 1 2 l 3 4')] 
+PASS CSS Animations: property <d> from [path('m 1 2 l 3 4 Z')] to [path('m 1 2 l 3 4')] at (1.5) is [path('m 1 2 l 3 4')] 
+PASS CSS Animations: property <d> from [path('m 0 0 Z')] to [path('m 0 0 Z')] at (-0.4) is [path('m 0 0 Z')] 
+PASS CSS Animations: property <d> from [path('m 0 0 Z')] to [path('m 0 0 Z')] at (0) is [path('m 0 0 Z')] 
+PASS CSS Animations: property <d> from [path('m 0 0 Z')] to [path('m 0 0 Z')] at (0.2) is [path('m 0 0 Z')] 
+PASS CSS Animations: property <d> from [path('m 0 0 Z')] to [path('m 0 0 Z')] at (0.6) is [path('m 0 0 Z')] 
+PASS CSS Animations: property <d> from [path('m 0 0 Z')] to [path('m 0 0 Z')] at (1) is [path('m 0 0 Z')] 
+PASS CSS Animations: property <d> from [path('m 0 0 Z')] to [path('m 0 0 Z')] at (1.4) is [path('m 0 0 Z')] 
+PASS CSS Animations: property <d> from [path('M 20 50')] to [path('M 30 70')] at (-0.4) is [path('M 16 42')] 
+PASS CSS Animations: property <d> from [path('M 20 50')] to [path('M 30 70')] at (0) is [path('M 20 50')] 
+PASS CSS Animations: property <d> from [path('M 20 50')] to [path('M 30 70')] at (0.2) is [path('M 22 54')] 
+PASS CSS Animations: property <d> from [path('M 20 50')] to [path('M 30 70')] at (0.6) is [path('M 26 62')] 
+PASS CSS Animations: property <d> from [path('M 20 50')] to [path('M 30 70')] at (1) is [path('M 30 70')] 
+PASS CSS Animations: property <d> from [path('M 20 50')] to [path('M 30 70')] at (1.4) is [path('M 34 78')] 
+PASS CSS Animations: property <d> from [path('m 20 50')] to [path('m 30 70')] at (-0.4) is [path('m 16 42')] 
+PASS CSS Animations: property <d> from [path('m 20 50')] to [path('m 30 70')] at (0) is [path('m 20 50')] 
+PASS CSS Animations: property <d> from [path('m 20 50')] to [path('m 30 70')] at (0.2) is [path('m 22 54')] 
+PASS CSS Animations: property <d> from [path('m 20 50')] to [path('m 30 70')] at (0.6) is [path('m 26 62')] 
+PASS CSS Animations: property <d> from [path('m 20 50')] to [path('m 30 70')] at (1) is [path('m 30 70')] 
+PASS CSS Animations: property <d> from [path('m 20 50')] to [path('m 30 70')] at (1.4) is [path('m 34 78')] 
+PASS CSS Animations: property <d> from [path('m 0 0 L 20 50')] to [path('m 0 0 L 30 70')] at (-0.4) is [path('m 0 0 L 16 42')] 
+PASS CSS Animations: property <d> from [path('m 0 0 L 20 50')] to [path('m 0 0 L 30 70')] at (0) is [path('m 0 0 L 20 50')] 
+PASS CSS Animations: property <d> from [path('m 0 0 L 20 50')] to [path('m 0 0 L 30 70')] at (0.2) is [path('m 0 0 L 22 54')] 
+PASS CSS Animations: property <d> from [path('m 0 0 L 20 50')] to [path('m 0 0 L 30 70')] at (0.6) is [path('m 0 0 L 26 62')] 
+PASS CSS Animations: property <d> from [path('m 0 0 L 20 50')] to [path('m 0 0 L 30 70')] at (1) is [path('m 0 0 L 30 70')] 
+PASS CSS Animations: property <d> from [path('m 0 0 L 20 50')] to [path('m 0 0 L 30 70')] at (1.4) is [path('m 0 0 L 34 78')] 
+PASS CSS Animations: property <d> from [path('m 0 0 l 20 50')] to [path('m 0 0 l 30 70')] at (-0.4) is [path('m 0 0 l 16 42')] 
+PASS CSS Animations: property <d> from [path('m 0 0 l 20 50')] to [path('m 0 0 l 30 70')] at (0) is [path('m 0 0 l 20 50')] 
+PASS CSS Animations: property <d> from [path('m 0 0 l 20 50')] to [path('m 0 0 l 30 70')] at (0.2) is [path('m 0 0 l 22 54')] 
+PASS CSS Animations: property <d> from [path('m 0 0 l 20 50')] to [path('m 0 0 l 30 70')] at (0.6) is [path('m 0 0 l 26 62')] 
+PASS CSS Animations: property <d> from [path('m 0 0 l 20 50')] to [path('m 0 0 l 30 70')] at (1) is [path('m 0 0 l 30 70')] 
+PASS CSS Animations: property <d> from [path('m 0 0 l 20 50')] to [path('m 0 0 l 30 70')] at (1.4) is [path('m 0 0 l 34 78')] 
+PASS CSS Animations: property <d> from [path('m 0 0 C 32 42 52 62 12 22')] to [path('m 0 0 C 37 47 57 67 17 27')] at (-0.4) is [path('m 0 0 C 30 40 50 60 10 20')] 
+PASS CSS Animations: property <d> from [path('m 0 0 C 32 42 52 62 12 22')] to [path('m 0 0 C 37 47 57 67 17 27')] at (0) is [path('m 0 0 C 32 42 52 62 12 22')] 
+PASS CSS Animations: property <d> from [path('m 0 0 C 32 42 52 62 12 22')] to [path('m 0 0 C 37 47 57 67 17 27')] at (0.2) is [path('m 0 0 C 33 43 53 63 13 23')] 
+PASS CSS Animations: property <d> from [path('m 0 0 C 32 42 52 62 12 22')] to [path('m 0 0 C 37 47 57 67 17 27')] at (0.6) is [path('m 0 0 C 35 45 55 65 15 25')] 
+PASS CSS Animations: property <d> from [path('m 0 0 C 32 42 52 62 12 22')] to [path('m 0 0 C 37 47 57 67 17 27')] at (1) is [path('m 0 0 C 37 47 57 67 17 27')] 
+PASS CSS Animations: property <d> from [path('m 0 0 C 32 42 52 62 12 22')] to [path('m 0 0 C 37 47 57 67 17 27')] at (1.4) is [path('m 0 0 C 39 49 59 69 19 29')] 
+PASS CSS Animations: property <d> from [path('m 0 0 c 32 42 52 62 12 22')] to [path('m 0 0 c 37 47 57 67 17 27')] at (-0.4) is [path('m 0 0 c 30 40 50 60 10 20')] 
+PASS CSS Animations: property <d> from [path('m 0 0 c 32 42 52 62 12 22')] to [path('m 0 0 c 37 47 57 67 17 27')] at (0) is [path('m 0 0 c 32 42 52 62 12 22')] 
+PASS CSS Animations: property <d> from [path('m 0 0 c 32 42 52 62 12 22')] to [path('m 0 0 c 37 47 57 67 17 27')] at (0.2) is [path('m 0 0 c 33 43 53 63 13 23')] 
+PASS CSS Animations: property <d> from [path('m 0 0 c 32 42 52 62 12 22')] to [path('m 0 0 c 37 47 57 67 17 27')] at (0.6) is [path('m 0 0 c 35 45 55 65 15 25')] 
+PASS CSS Animations: property <d> from [path('m 0 0 c 32 42 52 62 12 22')] to [path('m 0 0 c 37 47 57 67 17 27')] at (1) is [path('m 0 0 c 37 47 57 67 17 27')] 
+PASS CSS Animations: property <d> from [path('m 0 0 c 32 42 52 62 12 22')] to [path('m 0 0 c 37 47 57 67 17 27')] at (1.4) is [path('m 0 0 c 39 49 59 69 19 29')] 
+PASS CSS Animations: property <d> from [path('m 0 0 Q 32 42 52 62')] to [path('m 0 0 Q 37 47 57 67')] at (-0.4) is [path('m 0 0 Q 30 40 50 60')] 
+PASS CSS Animations: property <d> from [path('m 0 0 Q 32 42 52 62')] to [path('m 0 0 Q 37 47 57 67')] at (0) is [path('m 0 0 Q 32 42 52 62')] 
+PASS CSS Animations: property <d> from [path('m 0 0 Q 32 42 52 62')] to [path('m 0 0 Q 37 47 57 67')] at (0.2) is [path('m 0 0 Q 33 43 53 63')] 
+PASS CSS Animations: property <d> from [path('m 0 0 Q 32 42 52 62')] to [path('m 0 0 Q 37 47 57 67')] at (0.6) is [path('m 0 0 Q 35 45 55 65')] 
+PASS CSS Animations: property <d> from [path('m 0 0 Q 32 42 52 62')] to [path('m 0 0 Q 37 47 57 67')] at (1) is [path('m 0 0 Q 37 47 57 67')] 
+PASS CSS Animations: property <d> from [path('m 0 0 Q 32 42 52 62')] to [path('m 0 0 Q 37 47 57 67')] at (1.4) is [path('m 0 0 Q 39 49 59 69')] 
+PASS CSS Animations: property <d> from [path('m 0 0 q 32 42 52 62')] to [path('m 0 0 q 37 47 57 67')] at (-0.4) is [path('m 0 0 q 30 40 50 60')] 
+PASS CSS Animations: property <d> from [path('m 0 0 q 32 42 52 62')] to [path('m 0 0 q 37 47 57 67')] at (0) is [path('m 0 0 q 32 42 52 62')] 
+PASS CSS Animations: property <d> from [path('m 0 0 q 32 42 52 62')] to [path('m 0 0 q 37 47 57 67')] at (0.2) is [path('m 0 0 q 33 43 53 63')] 
+PASS CSS Animations: property <d> from [path('m 0 0 q 32 42 52 62')] to [path('m 0 0 q 37 47 57 67')] at (0.6) is [path('m 0 0 q 35 45 55 65')] 
+PASS CSS Animations: property <d> from [path('m 0 0 q 32 42 52 62')] to [path('m 0 0 q 37 47 57 67')] at (1) is [path('m 0 0 q 37 47 57 67')] 
+PASS CSS Animations: property <d> from [path('m 0 0 q 32 42 52 62')] to [path('m 0 0 q 37 47 57 67')] at (1.4) is [path('m 0 0 q 39 49 59 69')] 
+PASS CSS Animations: property <d> from [path('m 0 0 A 10 20 30 1 0 40 50')] to [path('m 0 0 A 60 70 80 0 1 90 100')] at (-0.4) is [path('m 0 0 A -10 0 10 1 0 20 30')] 
+PASS CSS Animations: property <d> from [path('m 0 0 A 10 20 30 1 0 40 50')] to [path('m 0 0 A 60 70 80 0 1 90 100')] at (0) is [path('m 0 0 A 10 20 30 1 0 40 50')] 
+PASS CSS Animations: property <d> from [path('m 0 0 A 10 20 30 1 0 40 50')] to [path('m 0 0 A 60 70 80 0 1 90 100')] at (0.2) is [path('m 0 0 A 20 30 40 1 0 50 60')] 
+PASS CSS Animations: property <d> from [path('m 0 0 A 10 20 30 1 0 40 50')] to [path('m 0 0 A 60 70 80 0 1 90 100')] at (0.6) is [path('m 0 0 A 40 50 60 0 1 70 80')] 
+PASS CSS Animations: property <d> from [path('m 0 0 A 10 20 30 1 0 40 50')] to [path('m 0 0 A 60 70 80 0 1 90 100')] at (1) is [path('m 0 0 A 60 70 80 0 1 90 100')] 
+PASS CSS Animations: property <d> from [path('m 0 0 A 10 20 30 1 0 40 50')] to [path('m 0 0 A 60 70 80 0 1 90 100')] at (1.4) is [path('m 0 0 A 80 90 100 0 1 110 120')] 
+PASS CSS Animations: property <d> from [path('m 0 0 a 10 20 30 1 0 40 50')] to [path('m 0 0 a 60 70 80 0 1 90 100')] at (-0.4) is [path('m 0 0 a -10 0 10 1 0 20 30')] 
+PASS CSS Animations: property <d> from [path('m 0 0 a 10 20 30 1 0 40 50')] to [path('m 0 0 a 60 70 80 0 1 90 100')] at (0) is [path('m 0 0 a 10 20 30 1 0 40 50')] 
+PASS CSS Animations: property <d> from [path('m 0 0 a 10 20 30 1 0 40 50')] to [path('m 0 0 a 60 70 80 0 1 90 100')] at (0.2) is [path('m 0 0 a 20 30 40 1 0 50 60')] 
+PASS CSS Animations: property <d> from [path('m 0 0 a 10 20 30 1 0 40 50')] to [path('m 0 0 a 60 70 80 0 1 90 100')] at (0.6) is [path('m 0 0 a 40 50 60 0 1 70 80')] 
+PASS CSS Animations: property <d> from [path('m 0 0 a 10 20 30 1 0 40 50')] to [path('m 0 0 a 60 70 80 0 1 90 100')] at (1) is [path('m 0 0 a 60 70 80 0 1 90 100')] 
+PASS CSS Animations: property <d> from [path('m 0 0 a 10 20 30 1 0 40 50')] to [path('m 0 0 a 60 70 80 0 1 90 100')] at (1.4) is [path('m 0 0 a 80 90 100 0 1 110 120')] 
+PASS CSS Animations: property <d> from [path('m 0 0 H 10')] to [path('m 0 0 H 60')] at (-0.4) is [path('m 0 0 H -10')] 
+PASS CSS Animations: property <d> from [path('m 0 0 H 10')] to [path('m 0 0 H 60')] at (0) is [path('m 0 0 H 10')] 
+PASS CSS Animations: property <d> from [path('m 0 0 H 10')] to [path('m 0 0 H 60')] at (0.2) is [path('m 0 0 H 20')] 
+PASS CSS Animations: property <d> from [path('m 0 0 H 10')] to [path('m 0 0 H 60')] at (0.6) is [path('m 0 0 H 40')] 
+PASS CSS Animations: property <d> from [path('m 0 0 H 10')] to [path('m 0 0 H 60')] at (1) is [path('m 0 0 H 60')] 
+PASS CSS Animations: property <d> from [path('m 0 0 H 10')] to [path('m 0 0 H 60')] at (1.4) is [path('m 0 0 H 80')] 
+PASS CSS Animations: property <d> from [path('m 0 0 h 10')] to [path('m 0 0 h 60')] at (-0.4) is [path('m 0 0 h -10')] 
+PASS CSS Animations: property <d> from [path('m 0 0 h 10')] to [path('m 0 0 h 60')] at (0) is [path('m 0 0 h 10')] 
+PASS CSS Animations: property <d> from [path('m 0 0 h 10')] to [path('m 0 0 h 60')] at (0.2) is [path('m 0 0 h 20')] 
+PASS CSS Animations: property <d> from [path('m 0 0 h 10')] to [path('m 0 0 h 60')] at (0.6) is [path('m 0 0 h 40')] 
+PASS CSS Animations: property <d> from [path('m 0 0 h 10')] to [path('m 0 0 h 60')] at (1) is [path('m 0 0 h 60')] 
+PASS CSS Animations: property <d> from [path('m 0 0 h 10')] to [path('m 0 0 h 60')] at (1.4) is [path('m 0 0 h 80')] 
+PASS CSS Animations: property <d> from [path('m 0 0 V 10')] to [path('m 0 0 V 60')] at (-0.4) is [path('m 0 0 V -10')] 
+PASS CSS Animations: property <d> from [path('m 0 0 V 10')] to [path('m 0 0 V 60')] at (0) is [path('m 0 0 V 10')] 
+PASS CSS Animations: property <d> from [path('m 0 0 V 10')] to [path('m 0 0 V 60')] at (0.2) is [path('m 0 0 V 20')] 
+PASS CSS Animations: property <d> from [path('m 0 0 V 10')] to [path('m 0 0 V 60')] at (0.6) is [path('m 0 0 V 40')] 
+PASS CSS Animations: property <d> from [path('m 0 0 V 10')] to [path('m 0 0 V 60')] at (1) is [path('m 0 0 V 60')] 
+PASS CSS Animations: property <d> from [path('m 0 0 V 10')] to [path('m 0 0 V 60')] at (1.4) is [path('m 0 0 V 80')] 
+PASS CSS Animations: property <d> from [path('m 0 0 v 10')] to [path('m 0 0 v 60')] at (-0.4) is [path('m 0 0 v -10')] 
+PASS CSS Animations: property <d> from [path('m 0 0 v 10')] to [path('m 0 0 v 60')] at (0) is [path('m 0 0 v 10')] 
+PASS CSS Animations: property <d> from [path('m 0 0 v 10')] to [path('m 0 0 v 60')] at (0.2) is [path('m 0 0 v 20')] 
+PASS CSS Animations: property <d> from [path('m 0 0 v 10')] to [path('m 0 0 v 60')] at (0.6) is [path('m 0 0 v 40')] 
+PASS CSS Animations: property <d> from [path('m 0 0 v 10')] to [path('m 0 0 v 60')] at (1) is [path('m 0 0 v 60')] 
+PASS CSS Animations: property <d> from [path('m 0 0 v 10')] to [path('m 0 0 v 60')] at (1.4) is [path('m 0 0 v 80')] 
+PASS CSS Animations: property <d> from [path('m 0 0 S 32 42 52 62')] to [path('m 0 0 S 37 47 57 67')] at (-0.4) is [path('m 0 0 S 30 40 50 60')] 
+PASS CSS Animations: property <d> from [path('m 0 0 S 32 42 52 62')] to [path('m 0 0 S 37 47 57 67')] at (0) is [path('m 0 0 S 32 42 52 62')] 
+PASS CSS Animations: property <d> from [path('m 0 0 S 32 42 52 62')] to [path('m 0 0 S 37 47 57 67')] at (0.2) is [path('m 0 0 S 33 43 53 63')] 
+PASS CSS Animations: property <d> from [path('m 0 0 S 32 42 52 62')] to [path('m 0 0 S 37 47 57 67')] at (0.6) is [path('m 0 0 S 35 45 55 65')] 
+PASS CSS Animations: property <d> from [path('m 0 0 S 32 42 52 62')] to [path('m 0 0 S 37 47 57 67')] at (1) is [path('m 0 0 S 37 47 57 67')] 
+PASS CSS Animations: property <d> from [path('m 0 0 S 32 42 52 62')] to [path('m 0 0 S 37 47 57 67')] at (1.4) is [path('m 0 0 S 39 49 59 69')] 
+PASS CSS Animations: property <d> from [path('m 0 0 s 32 42 52 62')] to [path('m 0 0 s 37 47 57 67')] at (-0.4) is [path('m 0 0 s 30 40 50 60')] 
+PASS CSS Animations: property <d> from [path('m 0 0 s 32 42 52 62')] to [path('m 0 0 s 37 47 57 67')] at (0) is [path('m 0 0 s 32 42 52 62')] 
+PASS CSS Animations: property <d> from [path('m 0 0 s 32 42 52 62')] to [path('m 0 0 s 37 47 57 67')] at (0.2) is [path('m 0 0 s 33 43 53 63')] 
+PASS CSS Animations: property <d> from [path('m 0 0 s 32 42 52 62')] to [path('m 0 0 s 37 47 57 67')] at (0.6) is [path('m 0 0 s 35 45 55 65')] 
+PASS CSS Animations: property <d> from [path('m 0 0 s 32 42 52 62')] to [path('m 0 0 s 37 47 57 67')] at (1) is [path('m 0 0 s 37 47 57 67')] 
+PASS CSS Animations: property <d> from [path('m 0 0 s 32 42 52 62')] to [path('m 0 0 s 37 47 57 67')] at (1.4) is [path('m 0 0 s 39 49 59 69')] 
+PASS CSS Animations: property <d> from [path('m 0 0 T 20 50')] to [path('m 0 0 T 30 70')] at (-0.4) is [path('m 0 0 T 16 42')] 
+PASS CSS Animations: property <d> from [path('m 0 0 T 20 50')] to [path('m 0 0 T 30 70')] at (0) is [path('m 0 0 T 20 50')] 
+PASS CSS Animations: property <d> from [path('m 0 0 T 20 50')] to [path('m 0 0 T 30 70')] at (0.2) is [path('m 0 0 T 22 54')] 
+PASS CSS Animations: property <d> from [path('m 0 0 T 20 50')] to [path('m 0 0 T 30 70')] at (0.6) is [path('m 0 0 T 26 62')] 
+PASS CSS Animations: property <d> from [path('m 0 0 T 20 50')] to [path('m 0 0 T 30 70')] at (1) is [path('m 0 0 T 30 70')] 
+PASS CSS Animations: property <d> from [path('m 0 0 T 20 50')] to [path('m 0 0 T 30 70')] at (1.4) is [path('m 0 0 T 34 78')] 
+PASS CSS Animations: property <d> from [path('m 0 0 t 20 50')] to [path('m 0 0 t 30 70')] at (-0.4) is [path('m 0 0 t 16 42')] 
+PASS CSS Animations: property <d> from [path('m 0 0 t 20 50')] to [path('m 0 0 t 30 70')] at (0) is [path('m 0 0 t 20 50')] 
+PASS CSS Animations: property <d> from [path('m 0 0 t 20 50')] to [path('m 0 0 t 30 70')] at (0.2) is [path('m 0 0 t 22 54')] 
+PASS CSS Animations: property <d> from [path('m 0 0 t 20 50')] to [path('m 0 0 t 30 70')] at (0.6) is [path('m 0 0 t 26 62')] 
+PASS CSS Animations: property <d> from [path('m 0 0 t 20 50')] to [path('m 0 0 t 30 70')] at (1) is [path('m 0 0 t 30 70')] 
+PASS CSS Animations: property <d> from [path('m 0 0 t 20 50')] to [path('m 0 0 t 30 70')] at (1.4) is [path('m 0 0 t 34 78')] 
+PASS CSS Animations: property <d> from [path('M 0 0 L 100 100 M 100 200 L 200 200 Z L 200 100 Z')] to [path('M 0 0 L 100 100 m 0 100 l 100 0 z l 200 100 z')] at (-0.4) is [path('M 0 0 L 100 100 m 0 100 l 100 0 Z l 60 -180 Z')] 
+PASS CSS Animations: property <d> from [path('M 0 0 L 100 100 M 100 200 L 200 200 Z L 200 100 Z')] to [path('M 0 0 L 100 100 m 0 100 l 100 0 z l 200 100 z')] at (0) is [path('M 0 0 L 100 100 M 100 200 L 200 200 Z L 200 100 Z')] 
+PASS CSS Animations: property <d> from [path('M 0 0 L 100 100 M 100 200 L 200 200 Z L 200 100 Z')] to [path('M 0 0 L 100 100 m 0 100 l 100 0 z l 200 100 z')] at (0.2) is [path('M 0 0 L 100 100 m 0 100 l 100 0 Z l 120 -60 Z')] 
+PASS CSS Animations: property <d> from [path('M 0 0 L 100 100 M 100 200 L 200 200 Z L 200 100 Z')] to [path('M 0 0 L 100 100 m 0 100 l 100 0 z l 200 100 z')] at (0.6) is [path('M 0 0 L 100 100 m 0 100 l 100 0 Z l 160 20 Z')] 
+PASS CSS Animations: property <d> from [path('M 0 0 L 100 100 M 100 200 L 200 200 Z L 200 100 Z')] to [path('M 0 0 L 100 100 m 0 100 l 100 0 z l 200 100 z')] at (1) is [path('M 0 0 L 100 100 m 0 100 l 100 0 Z l 200 100 Z')] 
+PASS CSS Animations: property <d> from [path('M 0 0 L 100 100 M 100 200 L 200 200 Z L 200 100 Z')] to [path('M 0 0 L 100 100 m 0 100 l 100 0 z l 200 100 z')] at (1.4) is [path('M 0 0 L 100 100 m 0 100 l 100 0 Z l 240 180 Z')] 
+PASS CSS Animations: property <d> from [path('M 0 0 L 100 100 M 100 200 L 200 200 Z L 200 100 Z')] to [path('M 0 0 L 100 100 m 0 100 l 100 0 z l 100 -100 z')] at (-0.4) is [path('M 0 0 L 100 100 m 0 100 l 100 0 Z l 100 -100 Z')] 
+PASS CSS Animations: property <d> from [path('M 0 0 L 100 100 M 100 200 L 200 200 Z L 200 100 Z')] to [path('M 0 0 L 100 100 m 0 100 l 100 0 z l 100 -100 z')] at (0) is [path('M 0 0 L 100 100 M 100 200 L 200 200 Z L 200 100 Z')] 
+PASS CSS Animations: property <d> from [path('M 0 0 L 100 100 M 100 200 L 200 200 Z L 200 100 Z')] to [path('M 0 0 L 100 100 m 0 100 l 100 0 z l 100 -100 z')] at (0.2) is [path('M 0 0 L 100 100 m 0 100 l 100 0 Z l 100 -100 Z')] 
+PASS CSS Animations: property <d> from [path('M 0 0 L 100 100 M 100 200 L 200 200 Z L 200 100 Z')] to [path('M 0 0 L 100 100 m 0 100 l 100 0 z l 100 -100 z')] at (0.6) is [path('M 0 0 L 100 100 m 0 100 l 100 0 Z l 100 -100 Z')] 
+PASS CSS Animations: property <d> from [path('M 0 0 L 100 100 M 100 200 L 200 200 Z L 200 100 Z')] to [path('M 0 0 L 100 100 m 0 100 l 100 0 z l 100 -100 z')] at (1) is [path('M 0 0 L 100 100 m 0 100 l 100 0 Z l 100 -100 Z')] 
+PASS CSS Animations: property <d> from [path('M 0 0 L 100 100 M 100 200 L 200 200 Z L 200 100 Z')] to [path('M 0 0 L 100 100 m 0 100 l 100 0 z l 100 -100 z')] at (1.4) is [path('M 0 0 L 100 100 m 0 100 l 100 0 Z l 100 -100 Z')] 
+PASS CSS Animations: property <d> from [path('m 10 20 l 20 30 z l 50 60 z m 70 80 l 90 60 z t 70 120')] to [path('M 110 120 L 130 150 Z L 80 110 Z M 100 140 L 190 200 Z T 210 220')] at (-0.4) is [path('M -30 -20 L -10 10 Z L 52 68 Z M 72 84 L 162 144 Z T 126 220')] 
+PASS CSS Animations: property <d> from [path('m 10 20 l 20 30 z l 50 60 z m 70 80 l 90 60 z t 70 120')] to [path('M 110 120 L 130 150 Z L 80 110 Z M 100 140 L 190 200 Z T 210 220')] at (0) is [path('m 10 20 l 20 30 Z l 50 60 Z m 70 80 l 90 60 Z t 70 120')] 
+PASS CSS Animations: property <d> from [path('m 10 20 l 20 30 z l 50 60 z m 70 80 l 90 60 z t 70 120')] to [path('M 110 120 L 130 150 Z L 80 110 Z M 100 140 L 190 200 Z T 210 220')] at (0.2) is [path('M 30 40 L 50 70 Z L 64 86 Z M 84 108 L 174 168 Z T 162 220')] 
+PASS CSS Animations: property <d> from [path('m 10 20 l 20 30 z l 50 60 z m 70 80 l 90 60 z t 70 120')] to [path('M 110 120 L 130 150 Z L 80 110 Z M 100 140 L 190 200 Z T 210 220')] at (0.6) is [path('M 70 80 L 90 110 Z L 72 98 Z M 92 124 L 182 184 Z T 186 220')] 
+PASS CSS Animations: property <d> from [path('m 10 20 l 20 30 z l 50 60 z m 70 80 l 90 60 z t 70 120')] to [path('M 110 120 L 130 150 Z L 80 110 Z M 100 140 L 190 200 Z T 210 220')] at (1) is [path('M 110 120 L 130 150 Z L 80 110 Z M 100 140 L 190 200 Z T 210 220')] 
+PASS CSS Animations: property <d> from [path('m 10 20 l 20 30 z l 50 60 z m 70 80 l 90 60 z t 70 120')] to [path('M 110 120 L 130 150 Z L 80 110 Z M 100 140 L 190 200 Z T 210 220')] at (1.4) is [path('M 150 160 L 170 190 Z L 88 122 Z M 108 156 L 198 216 Z T 234 220')] 
+PASS CSS Animations: property <d> from [path('m 10 20 c 40 50 30 60 80 70 c 90 100 140 110 120 130')] to [path('M 110 120 C 140 150 130 160 180 170 C 290 300 340 310 320 330')] at (-0.4) is [path('M -30 -20 C 14 38 4 48 54 58 C 136 146 186 156 166 176')] 
+PASS CSS Animations: property <d> from [path('m 10 20 c 40 50 30 60 80 70 c 90 100 140 110 120 130')] to [path('M 110 120 C 140 150 130 160 180 170 C 290 300 340 310 320 330')] at (0) is [path('m 10 20 c 40 50 30 60 80 70 c 90 100 140 110 120 130')] 
+PASS CSS Animations: property <d> from [path('m 10 20 c 40 50 30 60 80 70 c 90 100 140 110 120 130')] to [path('M 110 120 C 140 150 130 160 180 170 C 290 300 340 310 320 330')] at (0.2) is [path('M 30 40 C 68 86 58 96 108 106 C 202 212 252 222 232 242')] 
+PASS CSS Animations: property <d> from [path('m 10 20 c 40 50 30 60 80 70 c 90 100 140 110 120 130')] to [path('M 110 120 C 140 150 130 160 180 170 C 290 300 340 310 320 330')] at (0.6) is [path('M 70 80 C 104 118 94 128 144 138 C 246 256 296 266 276 286')] 
+PASS CSS Animations: property <d> from [path('m 10 20 c 40 50 30 60 80 70 c 90 100 140 110 120 130')] to [path('M 110 120 C 140 150 130 160 180 170 C 290 300 340 310 320 330')] at (1) is [path('M 110 120 C 140 150 130 160 180 170 C 290 300 340 310 320 330')] 
+PASS CSS Animations: property <d> from [path('m 10 20 c 40 50 30 60 80 70 c 90 100 140 110 120 130')] to [path('M 110 120 C 140 150 130 160 180 170 C 290 300 340 310 320 330')] at (1.4) is [path('M 150 160 C 176 182 166 192 216 202 C 334 344 384 354 364 374')] 
+PASS CSS Animations: property <d> from [path('m 10 20 q 30 60 40 50 q 100 70 90 80')] to [path('M 110 120 Q 130 160 140 150 Q 200 170 190 180')] at (-0.4) is [path('M -30 -20 Q 4 48 14 38 Q 130 128 120 138')] 
+PASS CSS Animations: property <d> from [path('m 10 20 q 30 60 40 50 q 100 70 90 80')] to [path('M 110 120 Q 130 160 140 150 Q 200 170 190 180')] at (0) is [path('m 10 20 q 30 60 40 50 q 100 70 90 80')] 
+PASS CSS Animations: property <d> from [path('m 10 20 q 30 60 40 50 q 100 70 90 80')] to [path('M 110 120 Q 130 160 140 150 Q 200 170 190 180')] at (0.2) is [path('M 30 40 Q 58 96 68 86 Q 160 146 150 156')] 
+PASS CSS Animations: property <d> from [path('m 10 20 q 30 60 40 50 q 100 70 90 80')] to [path('M 110 120 Q 130 160 140 150 Q 200 170 190 180')] at (0.6) is [path('M 70 80 Q 94 128 104 118 Q 180 158 170 168')] 
+PASS CSS Animations: property <d> from [path('m 10 20 q 30 60 40 50 q 100 70 90 80')] to [path('M 110 120 Q 130 160 140 150 Q 200 170 190 180')] at (1) is [path('M 110 120 Q 130 160 140 150 Q 200 170 190 180')] 
+PASS CSS Animations: property <d> from [path('m 10 20 q 30 60 40 50 q 100 70 90 80')] to [path('M 110 120 Q 130 160 140 150 Q 200 170 190 180')] at (1.4) is [path('M 150 160 Q 166 192 176 182 Q 220 182 210 192')] 
+PASS CSS Animations: property <d> from [path('m 10 20 s 30 60 40 50 s 100 70 90 80')] to [path('M 110 120 S 130 160 140 150 S 200 170 190 180')] at (-0.4) is [path('M -30 -20 S 4 48 14 38 S 130 128 120 138')] 
+PASS CSS Animations: property <d> from [path('m 10 20 s 30 60 40 50 s 100 70 90 80')] to [path('M 110 120 S 130 160 140 150 S 200 170 190 180')] at (0) is [path('m 10 20 s 30 60 40 50 s 100 70 90 80')] 
+PASS CSS Animations: property <d> from [path('m 10 20 s 30 60 40 50 s 100 70 90 80')] to [path('M 110 120 S 130 160 140 150 S 200 170 190 180')] at (0.2) is [path('M 30 40 S 58 96 68 86 S 160 146 150 156')] 
+PASS CSS Animations: property <d> from [path('m 10 20 s 30 60 40 50 s 100 70 90 80')] to [path('M 110 120 S 130 160 140 150 S 200 170 190 180')] at (0.6) is [path('M 70 80 S 94 128 104 118 S 180 158 170 168')] 
+PASS CSS Animations: property <d> from [path('m 10 20 s 30 60 40 50 s 100 70 90 80')] to [path('M 110 120 S 130 160 140 150 S 200 170 190 180')] at (1) is [path('M 110 120 S 130 160 140 150 S 200 170 190 180')] 
+PASS CSS Animations: property <d> from [path('m 10 20 s 30 60 40 50 s 100 70 90 80')] to [path('M 110 120 S 130 160 140 150 S 200 170 190 180')] at (1.4) is [path('M 150 160 S 166 192 176 182 S 220 182 210 192')] 
+PASS CSS Animations: property <d> from [path('m 10 20 h 30 v 40 h 50 v 60 l 70 80')] to [path('M 110 120 H 130 V 140 H 250 V 260 L 270 280')] at (-0.4) is [path('M -30 -20 H 4 V 28 H 26 V 64 L 116 168')] 
+PASS CSS Animations: property <d> from [path('m 10 20 h 30 v 40 h 50 v 60 l 70 80')] to [path('M 110 120 H 130 V 140 H 250 V 260 L 270 280')] at (0) is [path('m 10 20 h 30 v 40 h 50 v 60 l 70 80')] 
+PASS CSS Animations: property <d> from [path('m 10 20 h 30 v 40 h 50 v 60 l 70 80')] to [path('M 110 120 H 130 V 140 H 250 V 260 L 270 280')] at (0.2) is [path('M 30 40 H 58 V 76 H 122 V 148 L 182 216')] 
+PASS CSS Animations: property <d> from [path('m 10 20 h 30 v 40 h 50 v 60 l 70 80')] to [path('M 110 120 H 130 V 140 H 250 V 260 L 270 280')] at (0.6) is [path('M 70 80 H 94 V 108 H 186 V 204 L 226 248')] 
+PASS CSS Animations: property <d> from [path('m 10 20 h 30 v 40 h 50 v 60 l 70 80')] to [path('M 110 120 H 130 V 140 H 250 V 260 L 270 280')] at (1) is [path('M 110 120 H 130 V 140 H 250 V 260 L 270 280')] 
+PASS CSS Animations: property <d> from [path('m 10 20 h 30 v 40 h 50 v 60 l 70 80')] to [path('M 110 120 H 130 V 140 H 250 V 260 L 270 280')] at (1.4) is [path('M 150 160 H 166 V 172 H 314 V 316 L 314 312')] 
+PASS CSS Animations: property <d> from [path('m 10 20 a 10 20 30 1 0 40 50 a 110 120 30 1 1 140 50')] to [path('M 20 30 A 60 70 80 0 1 90 100 A 160 170 80 0 1 90 100')] at (-0.4) is [path('M 6 16 A -10 0 10 1 0 34 58 A 90 100 10 1 1 230 128')] 
+PASS CSS Animations: property <d> from [path('m 10 20 a 10 20 30 1 0 40 50 a 110 120 30 1 1 140 50')] to [path('M 20 30 A 60 70 80 0 1 90 100 A 160 170 80 0 1 90 100')] at (0) is [path('m 10 20 a 10 20 30 1 0 40 50 a 110 120 30 1 1 140 50')] 
+PASS CSS Animations: property <d> from [path('m 10 20 a 10 20 30 1 0 40 50 a 110 120 30 1 1 140 50')] to [path('M 20 30 A 60 70 80 0 1 90 100 A 160 170 80 0 1 90 100')] at (0.2) is [path('M 12 22 A 20 30 40 1 0 58 76 A 120 130 40 1 1 170 116')] 
+PASS CSS Animations: property <d> from [path('m 10 20 a 10 20 30 1 0 40 50 a 110 120 30 1 1 140 50')] to [path('M 20 30 A 60 70 80 0 1 90 100 A 160 170 80 0 1 90 100')] at (0.6) is [path('M 16 26 A 40 50 60 0 1 74 88 A 140 150 60 0 1 130 108')] 
+PASS CSS Animations: property <d> from [path('m 10 20 a 10 20 30 1 0 40 50 a 110 120 30 1 1 140 50')] to [path('M 20 30 A 60 70 80 0 1 90 100 A 160 170 80 0 1 90 100')] at (1) is [path('M 20 30 A 60 70 80 0 1 90 100 A 160 170 80 0 1 90 100')] 
+PASS CSS Animations: property <d> from [path('m 10 20 a 10 20 30 1 0 40 50 a 110 120 30 1 1 140 50')] to [path('M 20 30 A 60 70 80 0 1 90 100 A 160 170 80 0 1 90 100')] at (1.4) is [path('M 24 34 A 80 90 100 0 1 106 112 A 180 190 100 0 1 50 92')] 
+PASS Web Animations: property <d> from [path('m 0 0 h 1 h 2')] to [path('m 0 0 h 3')] at (-0.3) is [path('m 0 0 h 1 h 2')] 
+PASS Web Animations: property <d> from [path('m 0 0 h 1 h 2')] to [path('m 0 0 h 3')] at (0) is [path('m 0 0 h 1 h 2')] 
+PASS Web Animations: property <d> from [path('m 0 0 h 1 h 2')] to [path('m 0 0 h 3')] at (0.3) is [path('m 0 0 h 1 h 2')] 
+PASS Web Animations: property <d> from [path('m 0 0 h 1 h 2')] to [path('m 0 0 h 3')] at (0.5) is [path('m 0 0 h 3')] 
+PASS Web Animations: property <d> from [path('m 0 0 h 1 h 2')] to [path('m 0 0 h 3')] at (0.6) is [path('m 0 0 h 3')] 
+PASS Web Animations: property <d> from [path('m 0 0 h 1 h 2')] to [path('m 0 0 h 3')] at (1) is [path('m 0 0 h 3')] 
+PASS Web Animations: property <d> from [path('m 0 0 h 1 h 2')] to [path('m 0 0 h 3')] at (1.5) is [path('m 0 0 h 3')] 
+PASS Web Animations: property <d> from [path('m 10 0 h 1')] to [path('m 20 0 v 2')] at (-0.3) is [path('m 10 0 h 1')] 
+PASS Web Animations: property <d> from [path('m 10 0 h 1')] to [path('m 20 0 v 2')] at (0) is [path('m 10 0 h 1')] 
+PASS Web Animations: property <d> from [path('m 10 0 h 1')] to [path('m 20 0 v 2')] at (0.3) is [path('m 10 0 h 1')] 
+PASS Web Animations: property <d> from [path('m 10 0 h 1')] to [path('m 20 0 v 2')] at (0.5) is [path('m 20 0 v 2')] 
+PASS Web Animations: property <d> from [path('m 10 0 h 1')] to [path('m 20 0 v 2')] at (0.6) is [path('m 20 0 v 2')] 
+PASS Web Animations: property <d> from [path('m 10 0 h 1')] to [path('m 20 0 v 2')] at (1) is [path('m 20 0 v 2')] 
+PASS Web Animations: property <d> from [path('m 10 0 h 1')] to [path('m 20 0 v 2')] at (1.5) is [path('m 20 0 v 2')] 
+PASS Web Animations: property <d> from [path('m 1 2 l 3 4 Z')] to [path('m 1 2 l 3 4')] at (-0.3) is [path('m 1 2 l 3 4 Z')] 
+PASS Web Animations: property <d> from [path('m 1 2 l 3 4 Z')] to [path('m 1 2 l 3 4')] at (0) is [path('m 1 2 l 3 4 Z')] 
+PASS Web Animations: property <d> from [path('m 1 2 l 3 4 Z')] to [path('m 1 2 l 3 4')] at (0.3) is [path('m 1 2 l 3 4 Z')] 
+PASS Web Animations: property <d> from [path('m 1 2 l 3 4 Z')] to [path('m 1 2 l 3 4')] at (0.5) is [path('m 1 2 l 3 4')] 
+PASS Web Animations: property <d> from [path('m 1 2 l 3 4 Z')] to [path('m 1 2 l 3 4')] at (0.6) is [path('m 1 2 l 3 4')] 
+PASS Web Animations: property <d> from [path('m 1 2 l 3 4 Z')] to [path('m 1 2 l 3 4')] at (1) is [path('m 1 2 l 3 4')] 
+PASS Web Animations: property <d> from [path('m 1 2 l 3 4 Z')] to [path('m 1 2 l 3 4')] at (1.5) is [path('m 1 2 l 3 4')] 
+PASS Web Animations: property <d> from [path('m 0 0 Z')] to [path('m 0 0 Z')] at (-0.4) is [path('m 0 0 Z')] 
+PASS Web Animations: property <d> from [path('m 0 0 Z')] to [path('m 0 0 Z')] at (0) is [path('m 0 0 Z')] 
+PASS Web Animations: property <d> from [path('m 0 0 Z')] to [path('m 0 0 Z')] at (0.2) is [path('m 0 0 Z')] 
+PASS Web Animations: property <d> from [path('m 0 0 Z')] to [path('m 0 0 Z')] at (0.6) is [path('m 0 0 Z')] 
+PASS Web Animations: property <d> from [path('m 0 0 Z')] to [path('m 0 0 Z')] at (1) is [path('m 0 0 Z')] 
+PASS Web Animations: property <d> from [path('m 0 0 Z')] to [path('m 0 0 Z')] at (1.4) is [path('m 0 0 Z')] 
+PASS Web Animations: property <d> from [path('M 20 50')] to [path('M 30 70')] at (-0.4) is [path('M 16 42')] 
+PASS Web Animations: property <d> from [path('M 20 50')] to [path('M 30 70')] at (0) is [path('M 20 50')] 
+PASS Web Animations: property <d> from [path('M 20 50')] to [path('M 30 70')] at (0.2) is [path('M 22 54')] 
+PASS Web Animations: property <d> from [path('M 20 50')] to [path('M 30 70')] at (0.6) is [path('M 26 62')] 
+PASS Web Animations: property <d> from [path('M 20 50')] to [path('M 30 70')] at (1) is [path('M 30 70')] 
+PASS Web Animations: property <d> from [path('M 20 50')] to [path('M 30 70')] at (1.4) is [path('M 34 78')] 
+PASS Web Animations: property <d> from [path('m 20 50')] to [path('m 30 70')] at (-0.4) is [path('m 16 42')] 
+PASS Web Animations: property <d> from [path('m 20 50')] to [path('m 30 70')] at (0) is [path('m 20 50')] 
+PASS Web Animations: property <d> from [path('m 20 50')] to [path('m 30 70')] at (0.2) is [path('m 22 54')] 
+PASS Web Animations: property <d> from [path('m 20 50')] to [path('m 30 70')] at (0.6) is [path('m 26 62')] 
+PASS Web Animations: property <d> from [path('m 20 50')] to [path('m 30 70')] at (1) is [path('m 30 70')] 
+PASS Web Animations: property <d> from [path('m 20 50')] to [path('m 30 70')] at (1.4) is [path('m 34 78')] 
+PASS Web Animations: property <d> from [path('m 0 0 L 20 50')] to [path('m 0 0 L 30 70')] at (-0.4) is [path('m 0 0 L 16 42')] 
+PASS Web Animations: property <d> from [path('m 0 0 L 20 50')] to [path('m 0 0 L 30 70')] at (0) is [path('m 0 0 L 20 50')] 
+PASS Web Animations: property <d> from [path('m 0 0 L 20 50')] to [path('m 0 0 L 30 70')] at (0.2) is [path('m 0 0 L 22 54')] 
+PASS Web Animations: property <d> from [path('m 0 0 L 20 50')] to [path('m 0 0 L 30 70')] at (0.6) is [path('m 0 0 L 26 62')] 
+PASS Web Animations: property <d> from [path('m 0 0 L 20 50')] to [path('m 0 0 L 30 70')] at (1) is [path('m 0 0 L 30 70')] 
+PASS Web Animations: property <d> from [path('m 0 0 L 20 50')] to [path('m 0 0 L 30 70')] at (1.4) is [path('m 0 0 L 34 78')] 
+PASS Web Animations: property <d> from [path('m 0 0 l 20 50')] to [path('m 0 0 l 30 70')] at (-0.4) is [path('m 0 0 l 16 42')] 
+PASS Web Animations: property <d> from [path('m 0 0 l 20 50')] to [path('m 0 0 l 30 70')] at (0) is [path('m 0 0 l 20 50')] 
+PASS Web Animations: property <d> from [path('m 0 0 l 20 50')] to [path('m 0 0 l 30 70')] at (0.2) is [path('m 0 0 l 22 54')] 
+PASS Web Animations: property <d> from [path('m 0 0 l 20 50')] to [path('m 0 0 l 30 70')] at (0.6) is [path('m 0 0 l 26 62')] 
+PASS Web Animations: property <d> from [path('m 0 0 l 20 50')] to [path('m 0 0 l 30 70')] at (1) is [path('m 0 0 l 30 70')] 
+PASS Web Animations: property <d> from [path('m 0 0 l 20 50')] to [path('m 0 0 l 30 70')] at (1.4) is [path('m 0 0 l 34 78')] 
+PASS Web Animations: property <d> from [path('m 0 0 C 32 42 52 62 12 22')] to [path('m 0 0 C 37 47 57 67 17 27')] at (-0.4) is [path('m 0 0 C 30 40 50 60 10 20')] 
+PASS Web Animations: property <d> from [path('m 0 0 C 32 42 52 62 12 22')] to [path('m 0 0 C 37 47 57 67 17 27')] at (0) is [path('m 0 0 C 32 42 52 62 12 22')] 
+PASS Web Animations: property <d> from [path('m 0 0 C 32 42 52 62 12 22')] to [path('m 0 0 C 37 47 57 67 17 27')] at (0.2) is [path('m 0 0 C 33 43 53 63 13 23')] 
+PASS Web Animations: property <d> from [path('m 0 0 C 32 42 52 62 12 22')] to [path('m 0 0 C 37 47 57 67 17 27')] at (0.6) is [path('m 0 0 C 35 45 55 65 15 25')] 
+PASS Web Animations: property <d> from [path('m 0 0 C 32 42 52 62 12 22')] to [path('m 0 0 C 37 47 57 67 17 27')] at (1) is [path('m 0 0 C 37 47 57 67 17 27')] 
+PASS Web Animations: property <d> from [path('m 0 0 C 32 42 52 62 12 22')] to [path('m 0 0 C 37 47 57 67 17 27')] at (1.4) is [path('m 0 0 C 39 49 59 69 19 29')] 
+PASS Web Animations: property <d> from [path('m 0 0 c 32 42 52 62 12 22')] to [path('m 0 0 c 37 47 57 67 17 27')] at (-0.4) is [path('m 0 0 c 30 40 50 60 10 20')] 
+PASS Web Animations: property <d> from [path('m 0 0 c 32 42 52 62 12 22')] to [path('m 0 0 c 37 47 57 67 17 27')] at (0) is [path('m 0 0 c 32 42 52 62 12 22')] 
+PASS Web Animations: property <d> from [path('m 0 0 c 32 42 52 62 12 22')] to [path('m 0 0 c 37 47 57 67 17 27')] at (0.2) is [path('m 0 0 c 33 43 53 63 13 23')] 
+PASS Web Animations: property <d> from [path('m 0 0 c 32 42 52 62 12 22')] to [path('m 0 0 c 37 47 57 67 17 27')] at (0.6) is [path('m 0 0 c 35 45 55 65 15 25')] 
+PASS Web Animations: property <d> from [path('m 0 0 c 32 42 52 62 12 22')] to [path('m 0 0 c 37 47 57 67 17 27')] at (1) is [path('m 0 0 c 37 47 57 67 17 27')] 
+PASS Web Animations: property <d> from [path('m 0 0 c 32 42 52 62 12 22')] to [path('m 0 0 c 37 47 57 67 17 27')] at (1.4) is [path('m 0 0 c 39 49 59 69 19 29')] 
+PASS Web Animations: property <d> from [path('m 0 0 Q 32 42 52 62')] to [path('m 0 0 Q 37 47 57 67')] at (-0.4) is [path('m 0 0 Q 30 40 50 60')] 
+PASS Web Animations: property <d> from [path('m 0 0 Q 32 42 52 62')] to [path('m 0 0 Q 37 47 57 67')] at (0) is [path('m 0 0 Q 32 42 52 62')] 
+PASS Web Animations: property <d> from [path('m 0 0 Q 32 42 52 62')] to [path('m 0 0 Q 37 47 57 67')] at (0.2) is [path('m 0 0 Q 33 43 53 63')] 
+PASS Web Animations: property <d> from [path('m 0 0 Q 32 42 52 62')] to [path('m 0 0 Q 37 47 57 67')] at (0.6) is [path('m 0 0 Q 35 45 55 65')] 
+PASS Web Animations: property <d> from [path('m 0 0 Q 32 42 52 62')] to [path('m 0 0 Q 37 47 57 67')] at (1) is [path('m 0 0 Q 37 47 57 67')] 
+PASS Web Animations: property <d> from [path('m 0 0 Q 32 42 52 62')] to [path('m 0 0 Q 37 47 57 67')] at (1.4) is [path('m 0 0 Q 39 49 59 69')] 
+PASS Web Animations: property <d> from [path('m 0 0 q 32 42 52 62')] to [path('m 0 0 q 37 47 57 67')] at (-0.4) is [path('m 0 0 q 30 40 50 60')] 
+PASS Web Animations: property <d> from [path('m 0 0 q 32 42 52 62')] to [path('m 0 0 q 37 47 57 67')] at (0) is [path('m 0 0 q 32 42 52 62')] 
+PASS Web Animations: property <d> from [path('m 0 0 q 32 42 52 62')] to [path('m 0 0 q 37 47 57 67')] at (0.2) is [path('m 0 0 q 33 43 53 63')] 
+PASS Web Animations: property <d> from [path('m 0 0 q 32 42 52 62')] to [path('m 0 0 q 37 47 57 67')] at (0.6) is [path('m 0 0 q 35 45 55 65')] 
+PASS Web Animations: property <d> from [path('m 0 0 q 32 42 52 62')] to [path('m 0 0 q 37 47 57 67')] at (1) is [path('m 0 0 q 37 47 57 67')] 
+PASS Web Animations: property <d> from [path('m 0 0 q 32 42 52 62')] to [path('m 0 0 q 37 47 57 67')] at (1.4) is [path('m 0 0 q 39 49 59 69')] 
+PASS Web Animations: property <d> from [path('m 0 0 A 10 20 30 1 0 40 50')] to [path('m 0 0 A 60 70 80 0 1 90 100')] at (-0.4) is [path('m 0 0 A -10 0 10 1 0 20 30')] 
+PASS Web Animations: property <d> from [path('m 0 0 A 10 20 30 1 0 40 50')] to [path('m 0 0 A 60 70 80 0 1 90 100')] at (0) is [path('m 0 0 A 10 20 30 1 0 40 50')] 
+PASS Web Animations: property <d> from [path('m 0 0 A 10 20 30 1 0 40 50')] to [path('m 0 0 A 60 70 80 0 1 90 100')] at (0.2) is [path('m 0 0 A 20 30 40 1 0 50 60')] 
+PASS Web Animations: property <d> from [path('m 0 0 A 10 20 30 1 0 40 50')] to [path('m 0 0 A 60 70 80 0 1 90 100')] at (0.6) is [path('m 0 0 A 40 50 60 0 1 70 80')] 
+PASS Web Animations: property <d> from [path('m 0 0 A 10 20 30 1 0 40 50')] to [path('m 0 0 A 60 70 80 0 1 90 100')] at (1) is [path('m 0 0 A 60 70 80 0 1 90 100')] 
+PASS Web Animations: property <d> from [path('m 0 0 A 10 20 30 1 0 40 50')] to [path('m 0 0 A 60 70 80 0 1 90 100')] at (1.4) is [path('m 0 0 A 80 90 100 0 1 110 120')] 
+PASS Web Animations: property <d> from [path('m 0 0 a 10 20 30 1 0 40 50')] to [path('m 0 0 a 60 70 80 0 1 90 100')] at (-0.4) is [path('m 0 0 a -10 0 10 1 0 20 30')] 
+PASS Web Animations: property <d> from [path('m 0 0 a 10 20 30 1 0 40 50')] to [path('m 0 0 a 60 70 80 0 1 90 100')] at (0) is [path('m 0 0 a 10 20 30 1 0 40 50')] 
+PASS Web Animations: property <d> from [path('m 0 0 a 10 20 30 1 0 40 50')] to [path('m 0 0 a 60 70 80 0 1 90 100')] at (0.2) is [path('m 0 0 a 20 30 40 1 0 50 60')] 
+PASS Web Animations: property <d> from [path('m 0 0 a 10 20 30 1 0 40 50')] to [path('m 0 0 a 60 70 80 0 1 90 100')] at (0.6) is [path('m 0 0 a 40 50 60 0 1 70 80')] 
+PASS Web Animations: property <d> from [path('m 0 0 a 10 20 30 1 0 40 50')] to [path('m 0 0 a 60 70 80 0 1 90 100')] at (1) is [path('m 0 0 a 60 70 80 0 1 90 100')] 
+PASS Web Animations: property <d> from [path('m 0 0 a 10 20 30 1 0 40 50')] to [path('m 0 0 a 60 70 80 0 1 90 100')] at (1.4) is [path('m 0 0 a 80 90 100 0 1 110 120')] 
+PASS Web Animations: property <d> from [path('m 0 0 H 10')] to [path('m 0 0 H 60')] at (-0.4) is [path('m 0 0 H -10')] 
+PASS Web Animations: property <d> from [path('m 0 0 H 10')] to [path('m 0 0 H 60')] at (0) is [path('m 0 0 H 10')] 
+PASS Web Animations: property <d> from [path('m 0 0 H 10')] to [path('m 0 0 H 60')] at (0.2) is [path('m 0 0 H 20')] 
+PASS Web Animations: property <d> from [path('m 0 0 H 10')] to [path('m 0 0 H 60')] at (0.6) is [path('m 0 0 H 40')] 
+PASS Web Animations: property <d> from [path('m 0 0 H 10')] to [path('m 0 0 H 60')] at (1) is [path('m 0 0 H 60')] 
+PASS Web Animations: property <d> from [path('m 0 0 H 10')] to [path('m 0 0 H 60')] at (1.4) is [path('m 0 0 H 80')] 
+PASS Web Animations: property <d> from [path('m 0 0 h 10')] to [path('m 0 0 h 60')] at (-0.4) is [path('m 0 0 h -10')] 
+PASS Web Animations: property <d> from [path('m 0 0 h 10')] to [path('m 0 0 h 60')] at (0) is [path('m 0 0 h 10')] 
+PASS Web Animations: property <d> from [path('m 0 0 h 10')] to [path('m 0 0 h 60')] at (0.2) is [path('m 0 0 h 20')] 
+PASS Web Animations: property <d> from [path('m 0 0 h 10')] to [path('m 0 0 h 60')] at (0.6) is [path('m 0 0 h 40')] 
+PASS Web Animations: property <d> from [path('m 0 0 h 10')] to [path('m 0 0 h 60')] at (1) is [path('m 0 0 h 60')] 
+PASS Web Animations: property <d> from [path('m 0 0 h 10')] to [path('m 0 0 h 60')] at (1.4) is [path('m 0 0 h 80')] 
+PASS Web Animations: property <d> from [path('m 0 0 V 10')] to [path('m 0 0 V 60')] at (-0.4) is [path('m 0 0 V -10')] 
+PASS Web Animations: property <d> from [path('m 0 0 V 10')] to [path('m 0 0 V 60')] at (0) is [path('m 0 0 V 10')] 
+PASS Web Animations: property <d> from [path('m 0 0 V 10')] to [path('m 0 0 V 60')] at (0.2) is [path('m 0 0 V 20')] 
+PASS Web Animations: property <d> from [path('m 0 0 V 10')] to [path('m 0 0 V 60')] at (0.6) is [path('m 0 0 V 40')] 
+PASS Web Animations: property <d> from [path('m 0 0 V 10')] to [path('m 0 0 V 60')] at (1) is [path('m 0 0 V 60')] 
+PASS Web Animations: property <d> from [path('m 0 0 V 10')] to [path('m 0 0 V 60')] at (1.4) is [path('m 0 0 V 80')] 
+PASS Web Animations: property <d> from [path('m 0 0 v 10')] to [path('m 0 0 v 60')] at (-0.4) is [path('m 0 0 v -10')] 
+PASS Web Animations: property <d> from [path('m 0 0 v 10')] to [path('m 0 0 v 60')] at (0) is [path('m 0 0 v 10')] 
+PASS Web Animations: property <d> from [path('m 0 0 v 10')] to [path('m 0 0 v 60')] at (0.2) is [path('m 0 0 v 20')] 
+PASS Web Animations: property <d> from [path('m 0 0 v 10')] to [path('m 0 0 v 60')] at (0.6) is [path('m 0 0 v 40')] 
+PASS Web Animations: property <d> from [path('m 0 0 v 10')] to [path('m 0 0 v 60')] at (1) is [path('m 0 0 v 60')] 
+PASS Web Animations: property <d> from [path('m 0 0 v 10')] to [path('m 0 0 v 60')] at (1.4) is [path('m 0 0 v 80')] 
+PASS Web Animations: property <d> from [path('m 0 0 S 32 42 52 62')] to [path('m 0 0 S 37 47 57 67')] at (-0.4) is [path('m 0 0 S 30 40 50 60')] 
+PASS Web Animations: property <d> from [path('m 0 0 S 32 42 52 62')] to [path('m 0 0 S 37 47 57 67')] at (0) is [path('m 0 0 S 32 42 52 62')] 
+PASS Web Animations: property <d> from [path('m 0 0 S 32 42 52 62')] to [path('m 0 0 S 37 47 57 67')] at (0.2) is [path('m 0 0 S 33 43 53 63')] 
+PASS Web Animations: property <d> from [path('m 0 0 S 32 42 52 62')] to [path('m 0 0 S 37 47 57 67')] at (0.6) is [path('m 0 0 S 35 45 55 65')] 
+PASS Web Animations: property <d> from [path('m 0 0 S 32 42 52 62')] to [path('m 0 0 S 37 47 57 67')] at (1) is [path('m 0 0 S 37 47 57 67')] 
+PASS Web Animations: property <d> from [path('m 0 0 S 32 42 52 62')] to [path('m 0 0 S 37 47 57 67')] at (1.4) is [path('m 0 0 S 39 49 59 69')] 
+PASS Web Animations: property <d> from [path('m 0 0 s 32 42 52 62')] to [path('m 0 0 s 37 47 57 67')] at (-0.4) is [path('m 0 0 s 30 40 50 60')] 
+PASS Web Animations: property <d> from [path('m 0 0 s 32 42 52 62')] to [path('m 0 0 s 37 47 57 67')] at (0) is [path('m 0 0 s 32 42 52 62')] 
+PASS Web Animations: property <d> from [path('m 0 0 s 32 42 52 62')] to [path('m 0 0 s 37 47 57 67')] at (0.2) is [path('m 0 0 s 33 43 53 63')] 
+PASS Web Animations: property <d> from [path('m 0 0 s 32 42 52 62')] to [path('m 0 0 s 37 47 57 67')] at (0.6) is [path('m 0 0 s 35 45 55 65')] 
+PASS Web Animations: property <d> from [path('m 0 0 s 32 42 52 62')] to [path('m 0 0 s 37 47 57 67')] at (1) is [path('m 0 0 s 37 47 57 67')] 
+PASS Web Animations: property <d> from [path('m 0 0 s 32 42 52 62')] to [path('m 0 0 s 37 47 57 67')] at (1.4) is [path('m 0 0 s 39 49 59 69')] 
+PASS Web Animations: property <d> from [path('m 0 0 T 20 50')] to [path('m 0 0 T 30 70')] at (-0.4) is [path('m 0 0 T 16 42')] 
+PASS Web Animations: property <d> from [path('m 0 0 T 20 50')] to [path('m 0 0 T 30 70')] at (0) is [path('m 0 0 T 20 50')] 
+PASS Web Animations: property <d> from [path('m 0 0 T 20 50')] to [path('m 0 0 T 30 70')] at (0.2) is [path('m 0 0 T 22 54')] 
+PASS Web Animations: property <d> from [path('m 0 0 T 20 50')] to [path('m 0 0 T 30 70')] at (0.6) is [path('m 0 0 T 26 62')] 
+PASS Web Animations: property <d> from [path('m 0 0 T 20 50')] to [path('m 0 0 T 30 70')] at (1) is [path('m 0 0 T 30 70')] 
+PASS Web Animations: property <d> from [path('m 0 0 T 20 50')] to [path('m 0 0 T 30 70')] at (1.4) is [path('m 0 0 T 34 78')] 
+PASS Web Animations: property <d> from [path('m 0 0 t 20 50')] to [path('m 0 0 t 30 70')] at (-0.4) is [path('m 0 0 t 16 42')] 
+PASS Web Animations: property <d> from [path('m 0 0 t 20 50')] to [path('m 0 0 t 30 70')] at (0) is [path('m 0 0 t 20 50')] 
+PASS Web Animations: property <d> from [path('m 0 0 t 20 50')] to [path('m 0 0 t 30 70')] at (0.2) is [path('m 0 0 t 22 54')] 
+PASS Web Animations: property <d> from [path('m 0 0 t 20 50')] to [path('m 0 0 t 30 70')] at (0.6) is [path('m 0 0 t 26 62')] 
+PASS Web Animations: property <d> from [path('m 0 0 t 20 50')] to [path('m 0 0 t 30 70')] at (1) is [path('m 0 0 t 30 70')] 
+PASS Web Animations: property <d> from [path('m 0 0 t 20 50')] to [path('m 0 0 t 30 70')] at (1.4) is [path('m 0 0 t 34 78')] 
+PASS Web Animations: property <d> from [path('M 0 0 L 100 100 M 100 200 L 200 200 Z L 200 100 Z')] to [path('M 0 0 L 100 100 m 0 100 l 100 0 z l 200 100 z')] at (-0.4) is [path('M 0 0 L 100 100 m 0 100 l 100 0 Z l 60 -180 Z')] 
+PASS Web Animations: property <d> from [path('M 0 0 L 100 100 M 100 200 L 200 200 Z L 200 100 Z')] to [path('M 0 0 L 100 100 m 0 100 l 100 0 z l 200 100 z')] at (0) is [path('M 0 0 L 100 100 M 100 200 L 200 200 Z L 200 100 Z')] 
+PASS Web Animations: property <d> from [path('M 0 0 L 100 100 M 100 200 L 200 200 Z L 200 100 Z')] to [path('M 0 0 L 100 100 m 0 100 l 100 0 z l 200 100 z')] at (0.2) is [path('M 0 0 L 100 100 m 0 100 l 100 0 Z l 120 -60 Z')] 
+PASS Web Animations: property <d> from [path('M 0 0 L 100 100 M 100 200 L 200 200 Z L 200 100 Z')] to [path('M 0 0 L 100 100 m 0 100 l 100 0 z l 200 100 z')] at (0.6) is [path('M 0 0 L 100 100 m 0 100 l 100 0 Z l 160 20 Z')] 
+PASS Web Animations: property <d> from [path('M 0 0 L 100 100 M 100 200 L 200 200 Z L 200 100 Z')] to [path('M 0 0 L 100 100 m 0 100 l 100 0 z l 200 100 z')] at (1) is [path('M 0 0 L 100 100 m 0 100 l 100 0 Z l 200 100 Z')] 
+PASS Web Animations: property <d> from [path('M 0 0 L 100 100 M 100 200 L 200 200 Z L 200 100 Z')] to [path('M 0 0 L 100 100 m 0 100 l 100 0 z l 200 100 z')] at (1.4) is [path('M 0 0 L 100 100 m 0 100 l 100 0 Z l 240 180 Z')] 
+PASS Web Animations: property <d> from [path('M 0 0 L 100 100 M 100 200 L 200 200 Z L 200 100 Z')] to [path('M 0 0 L 100 100 m 0 100 l 100 0 z l 100 -100 z')] at (-0.4) is [path('M 0 0 L 100 100 m 0 100 l 100 0 Z l 100 -100 Z')] 
+PASS Web Animations: property <d> from [path('M 0 0 L 100 100 M 100 200 L 200 200 Z L 200 100 Z')] to [path('M 0 0 L 100 100 m 0 100 l 100 0 z l 100 -100 z')] at (0) is [path('M 0 0 L 100 100 M 100 200 L 200 200 Z L 200 100 Z')] 
+PASS Web Animations: property <d> from [path('M 0 0 L 100 100 M 100 200 L 200 200 Z L 200 100 Z')] to [path('M 0 0 L 100 100 m 0 100 l 100 0 z l 100 -100 z')] at (0.2) is [path('M 0 0 L 100 100 m 0 100 l 100 0 Z l 100 -100 Z')] 
+PASS Web Animations: property <d> from [path('M 0 0 L 100 100 M 100 200 L 200 200 Z L 200 100 Z')] to [path('M 0 0 L 100 100 m 0 100 l 100 0 z l 100 -100 z')] at (0.6) is [path('M 0 0 L 100 100 m 0 100 l 100 0 Z l 100 -100 Z')] 
+PASS Web Animations: property <d> from [path('M 0 0 L 100 100 M 100 200 L 200 200 Z L 200 100 Z')] to [path('M 0 0 L 100 100 m 0 100 l 100 0 z l 100 -100 z')] at (1) is [path('M 0 0 L 100 100 m 0 100 l 100 0 Z l 100 -100 Z')] 
+PASS Web Animations: property <d> from [path('M 0 0 L 100 100 M 100 200 L 200 200 Z L 200 100 Z')] to [path('M 0 0 L 100 100 m 0 100 l 100 0 z l 100 -100 z')] at (1.4) is [path('M 0 0 L 100 100 m 0 100 l 100 0 Z l 100 -100 Z')] 
+PASS Web Animations: property <d> from [path('m 10 20 l 20 30 z l 50 60 z m 70 80 l 90 60 z t 70 120')] to [path('M 110 120 L 130 150 Z L 80 110 Z M 100 140 L 190 200 Z T 210 220')] at (-0.4) is [path('M -30 -20 L -10 10 Z L 52 68 Z M 72 84 L 162 144 Z T 126 220')] 
+PASS Web Animations: property <d> from [path('m 10 20 l 20 30 z l 50 60 z m 70 80 l 90 60 z t 70 120')] to [path('M 110 120 L 130 150 Z L 80 110 Z M 100 140 L 190 200 Z T 210 220')] at (0) is [path('m 10 20 l 20 30 Z l 50 60 Z m 70 80 l 90 60 Z t 70 120')] 
+PASS Web Animations: property <d> from [path('m 10 20 l 20 30 z l 50 60 z m 70 80 l 90 60 z t 70 120')] to [path('M 110 120 L 130 150 Z L 80 110 Z M 100 140 L 190 200 Z T 210 220')] at (0.2) is [path('M 30 40 L 50 70 Z L 64 86 Z M 84 108 L 174 168 Z T 162 220')] 
+PASS Web Animations: property <d> from [path('m 10 20 l 20 30 z l 50 60 z m 70 80 l 90 60 z t 70 120')] to [path('M 110 120 L 130 150 Z L 80 110 Z M 100 140 L 190 200 Z T 210 220')] at (0.6) is [path('M 70 80 L 90 110 Z L 72 98 Z M 92 124 L 182 184 Z T 186 220')] 
+PASS Web Animations: property <d> from [path('m 10 20 l 20 30 z l 50 60 z m 70 80 l 90 60 z t 70 120')] to [path('M 110 120 L 130 150 Z L 80 110 Z M 100 140 L 190 200 Z T 210 220')] at (1) is [path('M 110 120 L 130 150 Z L 80 110 Z M 100 140 L 190 200 Z T 210 220')] 
+PASS Web Animations: property <d> from [path('m 10 20 l 20 30 z l 50 60 z m 70 80 l 90 60 z t 70 120')] to [path('M 110 120 L 130 150 Z L 80 110 Z M 100 140 L 190 200 Z T 210 220')] at (1.4) is [path('M 150 160 L 170 190 Z L 88 122 Z M 108 156 L 198 216 Z T 234 220')] 
+PASS Web Animations: property <d> from [path('m 10 20 c 40 50 30 60 80 70 c 90 100 140 110 120 130')] to [path('M 110 120 C 140 150 130 160 180 170 C 290 300 340 310 320 330')] at (-0.4) is [path('M -30 -20 C 14 38 4 48 54 58 C 136 146 186 156 166 176')] 
+PASS Web Animations: property <d> from [path('m 10 20 c 40 50 30 60 80 70 c 90 100 140 110 120 130')] to [path('M 110 120 C 140 150 130 160 180 170 C 290 300 340 310 320 330')] at (0) is [path('m 10 20 c 40 50 30 60 80 70 c 90 100 140 110 120 130')] 
+PASS Web Animations: property <d> from [path('m 10 20 c 40 50 30 60 80 70 c 90 100 140 110 120 130')] to [path('M 110 120 C 140 150 130 160 180 170 C 290 300 340 310 320 330')] at (0.2) is [path('M 30 40 C 68 86 58 96 108 106 C 202 212 252 222 232 242')] 
+PASS Web Animations: property <d> from [path('m 10 20 c 40 50 30 60 80 70 c 90 100 140 110 120 130')] to [path('M 110 120 C 140 150 130 160 180 170 C 290 300 340 310 320 330')] at (0.6) is [path('M 70 80 C 104 118 94 128 144 138 C 246 256 296 266 276 286')] 
+PASS Web Animations: property <d> from [path('m 10 20 c 40 50 30 60 80 70 c 90 100 140 110 120 130')] to [path('M 110 120 C 140 150 130 160 180 170 C 290 300 340 310 320 330')] at (1) is [path('M 110 120 C 140 150 130 160 180 170 C 290 300 340 310 320 330')] 
+PASS Web Animations: property <d> from [path('m 10 20 c 40 50 30 60 80 70 c 90 100 140 110 120 130')] to [path('M 110 120 C 140 150 130 160 180 170 C 290 300 340 310 320 330')] at (1.4) is [path('M 150 160 C 176 182 166 192 216 202 C 334 344 384 354 364 374')] 
+PASS Web Animations: property <d> from [path('m 10 20 q 30 60 40 50 q 100 70 90 80')] to [path('M 110 120 Q 130 160 140 150 Q 200 170 190 180')] at (-0.4) is [path('M -30 -20 Q 4 48 14 38 Q 130 128 120 138')] 
+PASS Web Animations: property <d> from [path('m 10 20 q 30 60 40 50 q 100 70 90 80')] to [path('M 110 120 Q 130 160 140 150 Q 200 170 190 180')] at (0) is [path('m 10 20 q 30 60 40 50 q 100 70 90 80')] 
+PASS Web Animations: property <d> from [path('m 10 20 q 30 60 40 50 q 100 70 90 80')] to [path('M 110 120 Q 130 160 140 150 Q 200 170 190 180')] at (0.2) is [path('M 30 40 Q 58 96 68 86 Q 160 146 150 156')] 
+PASS Web Animations: property <d> from [path('m 10 20 q 30 60 40 50 q 100 70 90 80')] to [path('M 110 120 Q 130 160 140 150 Q 200 170 190 180')] at (0.6) is [path('M 70 80 Q 94 128 104 118 Q 180 158 170 168')] 
+PASS Web Animations: property <d> from [path('m 10 20 q 30 60 40 50 q 100 70 90 80')] to [path('M 110 120 Q 130 160 140 150 Q 200 170 190 180')] at (1) is [path('M 110 120 Q 130 160 140 150 Q 200 170 190 180')] 
+PASS Web Animations: property <d> from [path('m 10 20 q 30 60 40 50 q 100 70 90 80')] to [path('M 110 120 Q 130 160 140 150 Q 200 170 190 180')] at (1.4) is [path('M 150 160 Q 166 192 176 182 Q 220 182 210 192')] 
+PASS Web Animations: property <d> from [path('m 10 20 s 30 60 40 50 s 100 70 90 80')] to [path('M 110 120 S 130 160 140 150 S 200 170 190 180')] at (-0.4) is [path('M -30 -20 S 4 48 14 38 S 130 128 120 138')] 
+PASS Web Animations: property <d> from [path('m 10 20 s 30 60 40 50 s 100 70 90 80')] to [path('M 110 120 S 130 160 140 150 S 200 170 190 180')] at (0) is [path('m 10 20 s 30 60 40 50 s 100 70 90 80')] 
+PASS Web Animations: property <d> from [path('m 10 20 s 30 60 40 50 s 100 70 90 80')] to [path('M 110 120 S 130 160 140 150 S 200 170 190 180')] at (0.2) is [path('M 30 40 S 58 96 68 86 S 160 146 150 156')] 
+PASS Web Animations: property <d> from [path('m 10 20 s 30 60 40 50 s 100 70 90 80')] to [path('M 110 120 S 130 160 140 150 S 200 170 190 180')] at (0.6) is [path('M 70 80 S 94 128 104 118 S 180 158 170 168')] 
+PASS Web Animations: property <d> from [path('m 10 20 s 30 60 40 50 s 100 70 90 80')] to [path('M 110 120 S 130 160 140 150 S 200 170 190 180')] at (1) is [path('M 110 120 S 130 160 140 150 S 200 170 190 180')] 
+PASS Web Animations: property <d> from [path('m 10 20 s 30 60 40 50 s 100 70 90 80')] to [path('M 110 120 S 130 160 140 150 S 200 170 190 180')] at (1.4) is [path('M 150 160 S 166 192 176 182 S 220 182 210 192')] 
+PASS Web Animations: property <d> from [path('m 10 20 h 30 v 40 h 50 v 60 l 70 80')] to [path('M 110 120 H 130 V 140 H 250 V 260 L 270 280')] at (-0.4) is [path('M -30 -20 H 4 V 28 H 26 V 64 L 116 168')] 
+PASS Web Animations: property <d> from [path('m 10 20 h 30 v 40 h 50 v 60 l 70 80')] to [path('M 110 120 H 130 V 140 H 250 V 260 L 270 280')] at (0) is [path('m 10 20 h 30 v 40 h 50 v 60 l 70 80')] 
+PASS Web Animations: property <d> from [path('m 10 20 h 30 v 40 h 50 v 60 l 70 80')] to [path('M 110 120 H 130 V 140 H 250 V 260 L 270 280')] at (0.2) is [path('M 30 40 H 58 V 76 H 122 V 148 L 182 216')] 
+PASS Web Animations: property <d> from [path('m 10 20 h 30 v 40 h 50 v 60 l 70 80')] to [path('M 110 120 H 130 V 140 H 250 V 260 L 270 280')] at (0.6) is [path('M 70 80 H 94 V 108 H 186 V 204 L 226 248')] 
+PASS Web Animations: property <d> from [path('m 10 20 h 30 v 40 h 50 v 60 l 70 80')] to [path('M 110 120 H 130 V 140 H 250 V 260 L 270 280')] at (1) is [path('M 110 120 H 130 V 140 H 250 V 260 L 270 280')] 
+PASS Web Animations: property <d> from [path('m 10 20 h 30 v 40 h 50 v 60 l 70 80')] to [path('M 110 120 H 130 V 140 H 250 V 260 L 270 280')] at (1.4) is [path('M 150 160 H 166 V 172 H 314 V 316 L 314 312')] 
+PASS Web Animations: property <d> from [path('m 10 20 a 10 20 30 1 0 40 50 a 110 120 30 1 1 140 50')] to [path('M 20 30 A 60 70 80 0 1 90 100 A 160 170 80 0 1 90 100')] at (-0.4) is [path('M 6 16 A -10 0 10 1 0 34 58 A 90 100 10 1 1 230 128')] 
+PASS Web Animations: property <d> from [path('m 10 20 a 10 20 30 1 0 40 50 a 110 120 30 1 1 140 50')] to [path('M 20 30 A 60 70 80 0 1 90 100 A 160 170 80 0 1 90 100')] at (0) is [path('m 10 20 a 10 20 30 1 0 40 50 a 110 120 30 1 1 140 50')] 
+PASS Web Animations: property <d> from [path('m 10 20 a 10 20 30 1 0 40 50 a 110 120 30 1 1 140 50')] to [path('M 20 30 A 60 70 80 0 1 90 100 A 160 170 80 0 1 90 100')] at (0.2) is [path('M 12 22 A 20 30 40 1 0 58 76 A 120 130 40 1 1 170 116')] 
+PASS Web Animations: property <d> from [path('m 10 20 a 10 20 30 1 0 40 50 a 110 120 30 1 1 140 50')] to [path('M 20 30 A 60 70 80 0 1 90 100 A 160 170 80 0 1 90 100')] at (0.6) is [path('M 16 26 A 40 50 60 0 1 74 88 A 140 150 60 0 1 130 108')] 
+PASS Web Animations: property <d> from [path('m 10 20 a 10 20 30 1 0 40 50 a 110 120 30 1 1 140 50')] to [path('M 20 30 A 60 70 80 0 1 90 100 A 160 170 80 0 1 90 100')] at (1) is [path('M 20 30 A 60 70 80 0 1 90 100 A 160 170 80 0 1 90 100')] 
+PASS Web Animations: property <d> from [path('m 10 20 a 10 20 30 1 0 40 50 a 110 120 30 1 1 140 50')] to [path('M 20 30 A 60 70 80 0 1 90 100 A 160 170 80 0 1 90 100')] at (1.4) is [path('M 24 34 A 80 90 100 0 1 106 112 A 180 190 100 0 1 50 92')] 
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/animations/interpolation/svg-d-interpolation.html b/third_party/WebKit/LayoutTests/animations/interpolation/svg-d-interpolation.html
index 1766336..355816f 100644
--- a/third_party/WebKit/LayoutTests/animations/interpolation/svg-d-interpolation.html
+++ b/third_party/WebKit/LayoutTests/animations/interpolation/svg-d-interpolation.html
@@ -296,12 +296,12 @@
   from: "path('M 0 0 L 100 100 M 100 200 L 200 200 Z L 200 100 Z')",
   to: "path('M 0 0 L 100 100 m 0 100 l 100 0 z l 200 100 z')"
 }, [
-  {at: -0.4, is: "path('M 0 0 L 100 100 M 100 200 L 200 200 Z L 120 20 Z')"},
+  {at: -0.4, is: "path('M 0 0 L 100 100 m 0 100 l 100 0 Z l 60 -180 Z')"},
   {at: 0, is: "path('M 0 0 L 100 100 M 100 200 L 200 200 Z L 200 100 Z')"},
-  {at: 0.2, is: "path('M 0 0 L 100 100 M 100 200 L 200 200 Z L 240 140 Z')"},
-  {at: 0.6, is: "path('M 0 0 L 100 100 m 0 100 l 100 0 Z l 120 20 Z')"},
+  {at: 0.2, is: "path('M 0 0 L 100 100 m 0 100 l 100 0 Z l 120 -60 Z')"},
+  {at: 0.6, is: "path('M 0 0 L 100 100 m 0 100 l 100 0 Z l 160 20 Z')"},
   {at: 1, is: "path('M 0 0 L 100 100 m 0 100 l 100 0 Z l 200 100 Z')"},
-  {at: 1.4, is: "path('M 0 0 L 100 100 m 0 100 l 100 0 Z l 280 180 Z')"},
+  {at: 1.4, is: "path('M 0 0 L 100 100 m 0 100 l 100 0 Z l 240 180 Z')"},
 ]);
 
 assertInterpolation({
@@ -309,12 +309,12 @@
   from: "path('M 0 0 L 100 100 M 100 200 L 200 200 Z L 200 100 Z')",
   to: "path('M 0 0 L 100 100 m 0 100 l 100 0 z l 100 -100 z')"
 }, [
-  {at: -0.4, is: "path('M 0 0 L 100 100 M 100 200 L 200 200 Z L 160 100 Z')"},
+  {at: -0.4, is: "path('M 0 0 L 100 100 m 0 100 l 100 0 Z l 100 -100 Z')"},
   {at: 0, is: "path('M 0 0 L 100 100 M 100 200 L 200 200 Z L 200 100 Z')"},
-  {at: 0.2, is: "path('M 0 0 L 100 100 M 100 200 L 200 200 Z L 220 100 Z')"},
-  {at: 0.6, is: "path('M 0 0 L 100 100 m 0 100 l 100 0 Z l 60 -100 Z')"},
+  {at: 0.2, is: "path('M 0 0 L 100 100 m 0 100 l 100 0 Z l 100 -100 Z')"},
+  {at: 0.6, is: "path('M 0 0 L 100 100 m 0 100 l 100 0 Z l 100 -100 Z')"},
   {at: 1, is: "path('M 0 0 L 100 100 m 0 100 l 100 0 Z l 100 -100 Z')"},
-  {at: 1.4, is: "path('M 0 0 L 100 100 m 0 100 l 100 0 Z l 140 -100 Z')"},
+  {at: 1.4, is: "path('M 0 0 L 100 100 m 0 100 l 100 0 Z l 100 -100 Z')"},
 ]);
 
 assertInterpolation({
@@ -322,12 +322,12 @@
   from: "path('m 10 20 l 20 30 z l 50 60 z m 70 80 l 90 60 z t 70 120')",
   to: "path('M 110 120 L 130 150 Z L 80 110 Z M 100 140 L 190 200 Z T 210 220')"
 }, [
-  {at: -0.4, is: "path('m -30 -20 l 20 30 Z l 90 100 Z m 90 100 l 90 60 Z t 90 160')"},
+  {at: -0.4, is: "path('M -30 -20 L -10 10 Z L 52 68 Z M 72 84 L 162 144 Z T 126 220')"},
   {at: 0, is: "path('m 10 20 l 20 30 Z l 50 60 Z m 70 80 l 90 60 Z t 70 120')"},
-  {at: 0.2, is: "path('m 30 40 l 20 30 Z l 30 40 Z m 60 70 l 90 60 Z t 60 100')"},
-  {at: 0.6, is: "path('M 70 80 L 90 110 Z L 80 110 Z M 120 160 L 210 220 Z T 250 280')"},
+  {at: 0.2, is: "path('M 30 40 L 50 70 Z L 64 86 Z M 84 108 L 174 168 Z T 162 220')"},
+  {at: 0.6, is: "path('M 70 80 L 90 110 Z L 72 98 Z M 92 124 L 182 184 Z T 186 220')"},
   {at: 1, is: "path('M 110 120 L 130 150 Z L 80 110 Z M 100 140 L 190 200 Z T 210 220')"},
-  {at: 1.4, is: "path('M 150 160 L 170 190 Z L 80 110 Z M 80 120 L 170 180 Z T 170 160')"}
+  {at: 1.4, is: "path('M 150 160 L 170 190 Z L 88 122 Z M 108 156 L 198 216 Z T 234 220')"}
 ]);
 
 assertInterpolation({
@@ -335,9 +335,9 @@
   from: "path('m 10 20 c 40 50 30 60 80 70 c 90 100 140 110 120 130')",
   to: "path('M 110 120 C 140 150 130 160 180 170 C 290 300 340 310 320 330')"
 }, [
-  {at: -0.4, is: "path('m -30 -20 c 44 58 34 68 84 78 c 82 88 132 98 112 118')"},
+  {at: -0.4, is: "path('M -30 -20 C 14 38 4 48 54 58 C 136 146 186 156 166 176')"},
   {at: 0, is: "path('m 10 20 c 40 50 30 60 80 70 c 90 100 140 110 120 130')"},
-  {at: 0.2, is: "path('m 30 40 c 38 46 28 56 78 66 c 94 106 144 116 124 136')"},
+  {at: 0.2, is: "path('M 30 40 C 68 86 58 96 108 106 C 202 212 252 222 232 242')"},
   {at: 0.6, is: "path('M 70 80 C 104 118 94 128 144 138 C 246 256 296 266 276 286')"},
   {at: 1, is: "path('M 110 120 C 140 150 130 160 180 170 C 290 300 340 310 320 330')"},
   {at: 1.4, is: "path('M 150 160 C 176 182 166 192 216 202 C 334 344 384 354 364 374')"}
@@ -348,9 +348,9 @@
   from: "path('m 10 20 q 30 60 40 50 q 100 70 90 80')",
   to: "path('M 110 120 Q 130 160 140 150 Q 200 170 190 180')"
 }, [
-  {at: -0.4, is: "path('m -30 -20 q 34 68 44 58 q 116 90 106 100')"},
+  {at: -0.4, is: "path('M -30 -20 Q 4 48 14 38 Q 130 128 120 138')"},
   {at: 0, is: "path('m 10 20 q 30 60 40 50 q 100 70 90 80')"},
-  {at: 0.2, is: "path('m 30 40 q 28 56 38 46 q 92 60 82 70')"},
+  {at: 0.2, is: "path('M 30 40 Q 58 96 68 86 Q 160 146 150 156')"},
   {at: 0.6, is: "path('M 70 80 Q 94 128 104 118 Q 180 158 170 168')"},
   {at: 1, is: "path('M 110 120 Q 130 160 140 150 Q 200 170 190 180')"},
   {at: 1.4, is: "path('M 150 160 Q 166 192 176 182 Q 220 182 210 192')"}
@@ -361,9 +361,9 @@
   from: "path('m 10 20 s 30 60 40 50 s 100 70 90 80')",
   to: "path('M 110 120 S 130 160 140 150 S 200 170 190 180')"
 }, [
-  {at: -0.4, is: "path('m -30 -20 s 34 68 44 58 s 116 90 106 100')"},
+  {at: -0.4, is: "path('M -30 -20 S 4 48 14 38 S 130 128 120 138')"},
   {at: 0, is: "path('m 10 20 s 30 60 40 50 s 100 70 90 80')"},
-  {at: 0.2, is: "path('m 30 40 s 28 56 38 46 s 92 60 82 70')"},
+  {at: 0.2, is: "path('M 30 40 S 58 96 68 86 S 160 146 150 156')"},
   {at: 0.6, is: "path('M 70 80 S 94 128 104 118 S 180 158 170 168')"},
   {at: 1, is: "path('M 110 120 S 130 160 140 150 S 200 170 190 180')"},
   {at: 1.4, is: "path('M 150 160 S 166 192 176 182 S 220 182 210 192')"}
@@ -374,9 +374,9 @@
   from: "path('m 10 20 h 30 v 40 h 50 v 60 l 70 80')",
   to: "path('M 110 120 H 130 V 140 H 250 V 260 L 270 280')"
 }, [
-  {at: -0.4, is: "path('m -30 -20 h 34 v 48 h 22 v 36 l 90 104')"},
+  {at: -0.4, is: "path('M -30 -20 H 4 V 28 H 26 V 64 L 116 168')"},
   {at: 0, is: "path('m 10 20 h 30 v 40 h 50 v 60 l 70 80')"},
-  {at: 0.2, is: "path('m 30 40 h 28 v 36 h 64 v 72 l 60 68')"},
+  {at: 0.2, is: "path('M 30 40 H 58 V 76 H 122 V 148 L 182 216')"},
   {at: 0.6, is: "path('M 70 80 H 94 V 108 H 186 V 204 L 226 248')"},
   {at: 1, is: "path('M 110 120 H 130 V 140 H 250 V 260 L 270 280')"},
   {at: 1.4, is: "path('M 150 160 H 166 V 172 H 314 V 316 L 314 312')"}
@@ -387,9 +387,9 @@
   from: "path('m 10 20 a 10 20 30 1 0 40 50 a 110 120 30 1 1 140 50')",
   to: "path('M 20 30 A 60 70 80 0 1 90 100 A 160 170 80 0 1 90 100')"
 }, [
-  {at: -0.4, is: "path('m 6 16 a -10 0 10 1 0 28 42 a 90 100 10 1 1 196 70')"},
+  {at: -0.4, is: "path('M 6 16 A -10 0 10 1 0 34 58 A 90 100 10 1 1 230 128')"},
   {at: 0, is: "path('m 10 20 a 10 20 30 1 0 40 50 a 110 120 30 1 1 140 50')"},
-  {at: 0.2, is: "path('m 12 22 a 20 30 40 1 0 46 54 a 120 130 40 1 1 112 40')"},
+  {at: 0.2, is: "path('M 12 22 A 20 30 40 1 0 58 76 A 120 130 40 1 1 170 116')"},
   {at: 0.6, is: "path('M 16 26 A 40 50 60 0 1 74 88 A 140 150 60 0 1 130 108')"},
   {at: 1, is: "path('M 20 30 A 60 70 80 0 1 90 100 A 160 170 80 0 1 90 100')"},
   {at: 1.4, is: "path('M 24 34 A 80 90 100 0 1 106 112 A 180 190 100 0 1 50 92')"}
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/canvas-filter-width-height-expected.html b/third_party/WebKit/LayoutTests/fast/canvas/canvas-filter-width-height-expected.html
new file mode 100644
index 0000000..0e23e3f5
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/canvas/canvas-filter-width-height-expected.html
@@ -0,0 +1,7 @@
+<canvas id="canvas" width="100" height="100"></canvas>
+<script>
+var canvas = document.getElementById('canvas');
+var ctx = canvas.getContext('2d');
+ctx.fillStyle = '#0f0';
+ctx.fillRect(0, 0, 50, 40);
+</script>
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/canvas-filter-width-height-hidpi-expected.html b/third_party/WebKit/LayoutTests/fast/canvas/canvas-filter-width-height-hidpi-expected.html
new file mode 100644
index 0000000..d78ede2
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/canvas/canvas-filter-width-height-hidpi-expected.html
@@ -0,0 +1,17 @@
+<canvas id="canvas" width="100" height="100"></canvas>
+<script>
+function runTest() {
+    if (window.testRunner) {
+        testRunner.waitUntilDone();
+        testRunner.setBackingScaleFactor(2, function() {
+            var canvas = document.getElementById('canvas');
+            var ctx = canvas.getContext('2d');
+            ctx.fillStyle = '#0f0';
+            ctx.fillRect(0, 0, 50, 40);
+            testRunner.notifyDone();
+        });
+    }
+}
+
+window.onload = runTest;
+</script>
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/canvas-filter-width-height-hidpi-scale-expected.html b/third_party/WebKit/LayoutTests/fast/canvas/canvas-filter-width-height-hidpi-scale-expected.html
new file mode 100644
index 0000000..16e683c1
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/canvas/canvas-filter-width-height-hidpi-scale-expected.html
@@ -0,0 +1,19 @@
+<canvas id="canvas" width="100" height="100"></canvas>
+<script>
+function runTest() {
+    if (window.testRunner) {
+        testRunner.waitUntilDone();
+        testRunner.setBackingScaleFactor(2, function() {
+            var canvas = document.getElementById('canvas');
+            canvas.style.width = '50px';
+            canvas.style.height = '50px';
+            var ctx = canvas.getContext('2d');
+            ctx.fillStyle = '#0f0';
+            ctx.fillRect(0, 0, 50, 40);
+            testRunner.notifyDone();
+        });
+    }
+}
+
+window.onload = runTest;
+</script>
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/canvas-filter-width-height-hidpi-scale.html b/third_party/WebKit/LayoutTests/fast/canvas/canvas-filter-width-height-hidpi-scale.html
new file mode 100644
index 0000000..4319b5f0
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/canvas/canvas-filter-width-height-hidpi-scale.html
@@ -0,0 +1,29 @@
+<svg style="display: block; width: 0; height: 0">
+  <defs>
+    <filter id="crop" primitiveUnits="objectBoundingBox">
+      <femerge x="0" y="0" width="50%" height="40%">
+        <femergenode in="SourceGraphic"></femergenode>
+      </femerge>
+    </filter>
+  </defs>
+</svg>
+<canvas id="canvas" width="100" height="100"></canvas>
+<script>
+function runTest() {
+    if (window.testRunner) {
+        testRunner.waitUntilDone();
+        testRunner.setBackingScaleFactor(2, function() {
+            var canvas = document.getElementById('canvas');
+            canvas.style.width = '50px';
+            canvas.style.height = '50px';
+            var ctx = canvas.getContext('2d');
+            ctx.filter = 'url(#crop)';
+            ctx.fillStyle = '#0f0';
+            ctx.fillRect(0, 0, 90, 90);
+            testRunner.notifyDone();
+        });
+    }
+}
+
+window.onload = runTest;
+</script>
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/canvas-filter-width-height-hidpi.html b/third_party/WebKit/LayoutTests/fast/canvas/canvas-filter-width-height-hidpi.html
new file mode 100644
index 0000000..e5eae39
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/canvas/canvas-filter-width-height-hidpi.html
@@ -0,0 +1,27 @@
+<svg style="display: block; width: 0; height: 0">
+  <defs>
+    <filter id="crop" primitiveUnits="objectBoundingBox">
+      <femerge x="0" y="0" width="50%" height="40%">
+        <femergenode in="SourceGraphic"></femergenode>
+      </femerge>
+    </filter>
+  </defs>
+</svg>
+<canvas id="canvas" width="100" height="100"></canvas>
+<script>
+function runTest() {
+    if (window.testRunner) {
+        testRunner.waitUntilDone();
+        testRunner.setBackingScaleFactor(2, function() {
+            var canvas = document.getElementById('canvas');
+            var ctx = canvas.getContext('2d');
+            ctx.filter = 'url(#crop)';
+            ctx.fillStyle = '#0f0';
+            ctx.fillRect(0, 0, 90, 90);
+            testRunner.notifyDone();
+        });
+    }
+}
+
+window.onload = runTest;
+</script>
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/canvas-filter-width-height-scale-expected.html b/third_party/WebKit/LayoutTests/fast/canvas/canvas-filter-width-height-scale-expected.html
new file mode 100644
index 0000000..2b3e967d
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/canvas/canvas-filter-width-height-scale-expected.html
@@ -0,0 +1,9 @@
+<canvas id="canvas" width="100" height="100"></canvas>
+<script>
+var canvas = document.getElementById('canvas');
+canvas.style.width = '200px';
+canvas.style.height = '200px';
+var ctx = canvas.getContext('2d');
+ctx.fillStyle = '#0f0';
+ctx.fillRect(0, 0, 50, 40);
+</script>
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/canvas-filter-width-height-scale.html b/third_party/WebKit/LayoutTests/fast/canvas/canvas-filter-width-height-scale.html
new file mode 100644
index 0000000..78e8224b
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/canvas/canvas-filter-width-height-scale.html
@@ -0,0 +1,19 @@
+<svg style="display: block; width: 0; height: 0">
+  <defs>
+    <filter id="crop" primitiveUnits="objectBoundingBox">
+      <femerge x="0" y="0" width="50%" height="40%">
+        <femergenode in="SourceGraphic"></femergenode>
+      </femerge>
+    </filter>
+  </defs>
+</svg>
+<canvas id="canvas" width="100" height="100"></canvas>
+<script>
+var canvas = document.getElementById('canvas');
+canvas.style.width = '200px';
+canvas.style.height = '200px';
+var ctx = canvas.getContext('2d');
+ctx.filter = 'url(#crop)';
+ctx.fillStyle = '#0f0';
+ctx.fillRect(0, 0, 90, 90);
+</script>
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/canvas-filter-width-height.html b/third_party/WebKit/LayoutTests/fast/canvas/canvas-filter-width-height.html
new file mode 100644
index 0000000..1185895
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/canvas/canvas-filter-width-height.html
@@ -0,0 +1,17 @@
+<svg style="display: block; width: 0; height: 0">
+  <defs>
+    <filter id="crop" primitiveUnits="objectBoundingBox">
+      <femerge x="0" y="0" width="50%" height="40%">
+        <femergenode in="SourceGraphic"></femergenode>
+      </femerge>
+    </filter>
+  </defs>
+</svg>
+<canvas id="canvas" width="100" height="100"></canvas>
+<script>
+var canvas = document.getElementById('canvas');
+var ctx = canvas.getContext('2d');
+ctx.filter = 'url(#crop)';
+ctx.fillStyle = '#0f0';
+ctx.fillRect(0, 0, 90, 90);
+</script>
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/toBlob/canvas-toBlob-defaultpng.html b/third_party/WebKit/LayoutTests/fast/canvas/toBlob/canvas-toBlob-defaultpng.html
index 6f09ee8..c2fec4c 100644
--- a/third_party/WebKit/LayoutTests/fast/canvas/toBlob/canvas-toBlob-defaultpng.html
+++ b/third_party/WebKit/LayoutTests/fast/canvas/toBlob/canvas-toBlob-defaultpng.html
@@ -16,10 +16,11 @@
 
 var newImg = new Image();
 newImg.onload = function() {
-    ctx2.drawImage(newImg, 0, 0, 150, 75);
+    // 300x150 is the default size of the canvas, which is the source of the newImg.
+    ctx2.drawImage(newImg, 0, 0, 300, 150);
 
     var imageData1 = ctx.getImageData(0, 0, 150, 75).data;
-    var imageData2 = ctx.getImageData(0, 0, 150, 75).data;
+    var imageData2 = ctx2.getImageData(0, 0, 150, 75).data;
     var imageMatched = true;
     for (var i = 1; i < imageData1.length; i++)
     {
diff --git a/third_party/WebKit/LayoutTests/fast/dom/shadow/content-element-change-select-attribute-after-deleted-crash.html b/third_party/WebKit/LayoutTests/fast/dom/shadow/content-element-change-select-attribute-after-deleted-crash.html
new file mode 100644
index 0000000..f7ed27e
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/dom/shadow/content-element-change-select-attribute-after-deleted-crash.html
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<script src='../../../resources/testharness.js'></script>
+<script src='../../../resources/testharnessreport.js'></script>
+<div id=host1></div>
+<script>
+'use strict';
+const sr = host1.createShadowRoot();
+sr.innerHTML = '<div id="host2"></div>';
+const sr2 = sr.getElementById('host2').createShadowRoot();
+sr.innerHTML = null;
+// TODO(hayato): Find a more reliable way to reproduce the crash. This is the only reliable way as of now.
+// Using GCController.collect() does not reproduce the crash.
+for (var i = 1; i < 20000; i++) {
+  "abc" + i;
+}
+const selectTest = async_test("Testing select attribute change");
+setTimeout(() => {
+  selectTest.step(() => {
+    sr2.appendChild(document.createElement('content')).select = 'foo';
+  });
+  selectTest.done();
+}, 0);
+</script>
diff --git a/third_party/WebKit/LayoutTests/fast/events/touch/gesture/gesture-scroll-by-page-expected.txt b/third_party/WebKit/LayoutTests/fast/events/touch/gesture/gesture-scroll-by-page-expected.txt
new file mode 100644
index 0000000..645e28d3
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/events/touch/gesture/gesture-scroll-by-page-expected.txt
@@ -0,0 +1,10 @@
+This tests gesture scrolling by pages.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS document.scrollingElement.scrollTop >= window.innerHeight * 0.875 * 2 became true
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/third_party/WebKit/LayoutTests/fast/events/touch/gesture/gesture-scroll-by-page.html b/third_party/WebKit/LayoutTests/fast/events/touch/gesture/gesture-scroll-by-page.html
new file mode 100644
index 0000000..d2c4f0d
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/events/touch/gesture/gesture-scroll-by-page.html
@@ -0,0 +1,60 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="../../../../resources/js-test.js"></script>
+<style type="text/css">
+::-webkit-scrollbar {
+    width: 0px;
+    height: 0px;
+}
+
+#greenbox {
+  width: 100px;
+  height: 2000px;
+  background: green;
+}
+#redbox {
+  width: 100px;
+  height: 2000px;
+  background: red;
+}
+
+</style>
+</head>
+<body style="margin:0" onload="runTest();">
+
+<div id="greenbox"></div>
+<div id="redbox"></div>
+
+<p id="description"></p>
+<div id="console"></div>
+<script type="text/javascript">
+
+function gestureScroll()
+{
+    eventSender.gestureScrollBegin("touchpad", 10, 20);
+    eventSender.gestureScrollUpdate("touchpad", 0, -1, false, "Page");
+    eventSender.gestureScrollUpdate("touchpad", 0, -2, false, "Page");
+    eventSender.gestureScrollUpdate("touchpad", 0, 1, false, "Page");
+    eventSender.gestureScrollEnd("touchpad", 0, 0);
+
+    // see kMinFractionToStepWhenPaging in ScrollableArea.cppP
+    // 2 is the expected number of pages scrolled (-1 + -2 + 1)
+    shouldBecomeEqual("document.scrollingElement.scrollTop >= window.innerHeight * 0.875 * 2", "true", finishJSTest, 1000);
+}
+
+jsTestIsAsync = true;
+
+function runTest()
+{
+    if (window.eventSender) {
+        description('This tests gesture scrolling by pages.');
+        gestureScroll();
+    } else {
+        debug("This test requires DumpRenderTree.  Gesture-scroll the page to validate the implementation.");
+    }
+}
+</script>
+
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/fast/events/touch/gesture/gesture-scroll-by-pixel-expected.txt b/third_party/WebKit/LayoutTests/fast/events/touch/gesture/gesture-scroll-by-pixel-expected.txt
new file mode 100644
index 0000000..c557902
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/events/touch/gesture/gesture-scroll-by-pixel-expected.txt
@@ -0,0 +1,10 @@
+This tests gesture scrolling by non-precise pixels.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS document.scrollingElement.scrollTop became 295
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/third_party/WebKit/LayoutTests/fast/events/touch/gesture/gesture-scroll-by-pixel.html b/third_party/WebKit/LayoutTests/fast/events/touch/gesture/gesture-scroll-by-pixel.html
new file mode 100644
index 0000000..7338ece
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/events/touch/gesture/gesture-scroll-by-pixel.html
@@ -0,0 +1,58 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="../../../../resources/js-test.js"></script>
+<style type="text/css">
+::-webkit-scrollbar {
+    width: 0px;
+    height: 0px;
+}
+
+#greenbox {
+  width: 100px;
+  height: 2000px;
+  background: green;
+}
+#redbox {
+  width: 100px;
+  height: 2000px;
+  background: red;
+}
+
+</style>
+</head>
+<body style="margin:0" onload="runTest();">
+
+<div id="greenbox"></div>
+<div id="redbox"></div>
+
+<p id="description"></p>
+<div id="console"></div>
+<script type="text/javascript">
+
+function gestureScroll()
+{
+    eventSender.gestureScrollBegin("touchpad", 10, 20);
+    eventSender.gestureScrollUpdate("touchpad", 0, -100, false, "Pixels");
+    eventSender.gestureScrollUpdate("touchpad", 0, -215, false, "Pixels");
+    eventSender.gestureScrollUpdate("touchpad", 0, 20, false, "Pixels");
+    eventSender.gestureScrollEnd("touchpad", 0, 0);
+
+    shouldBecomeEqual("document.scrollingElement.scrollTop", "295", finishJSTest, 1000);
+}
+
+jsTestIsAsync = true;
+
+function runTest()
+{
+    if (window.eventSender) {
+        description('This tests gesture scrolling by non-precise pixels.');
+        gestureScroll();
+    } else {
+        debug("This test requires DumpRenderTree.  Gesture-scroll the page to validate the implementation.");
+    }
+}
+</script>
+
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/hittesting/culled-inline-expected.txt b/third_party/WebKit/LayoutTests/hittesting/culled-inline-expected.txt
new file mode 100644
index 0000000..3e92001
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/hittesting/culled-inline-expected.txt
@@ -0,0 +1,11 @@
+Hello World
+To manually test, hover between the two words to see if background color turns green.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS element.id is "culled"
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/third_party/WebKit/LayoutTests/hittesting/culled-inline.html b/third_party/WebKit/LayoutTests/hittesting/culled-inline.html
new file mode 100644
index 0000000..61fa8c2
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/hittesting/culled-inline.html
@@ -0,0 +1,36 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="../resources/js-test.js"></script>
+<style>
+#culled:hover {
+  background-color: green;
+}
+.left {
+  display: inline-block;
+  transform: translateY(0px);
+  border: 1px solid black;
+}
+.right {
+  margin-left: 200px;
+  border: 1px solid black;
+}
+</style>
+</head>
+<body>
+<div id="container">
+<span id="culled">
+    <span class="left">Hello</span>
+    <span class="right">World</span>
+</span>
+</div>
+<div id="console"></div>
+</body>
+<script>
+description('To manually test, hover between the two words to see if background color turns green.');
+
+var rect = document.getElementById('culled').getBoundingClientRect();
+element = document.elementFromPoint(rect.left + rect.width/2, rect.top + rect.height/2);
+shouldBeEqualToString('element.id', 'culled');
+</script>
+</html>
diff --git a/third_party/WebKit/LayoutTests/http/tests/serviceworker/fetch-event.html b/third_party/WebKit/LayoutTests/http/tests/serviceworker/fetch-event.html
index 8b9cb40..a27c2b9 100644
--- a/third_party/WebKit/LayoutTests/http/tests/serviceworker/fetch-event.html
+++ b/third_party/WebKit/LayoutTests/http/tests/serviceworker/fetch-event.html
@@ -69,6 +69,47 @@
   }, 'Service Worker responds to fetch event with the referrer URL');
 
 async_test(function(t) {
+    var scope = 'resources/simple.html?clientId';
+    var frame;
+    var client_id1, client_id2;
+    service_worker_unregister_and_register(t, worker, scope)
+      .then(function(reg) {
+          return wait_for_state(t, reg.installing, 'activated');
+        })
+      .then(function() { return with_iframe(scope); })
+      .then(function(f) {
+          frame = f;
+          assert_equals(
+            frame.contentDocument.body.textContent.substr(0, 19),
+            'Client ID Not Found',
+            'Service Worker should respond to navigation fetch with no ' +
+            'client id');
+          return frame.contentWindow.fetch('resources/other.html?clientId');
+        })
+      .then(function(response) { return response.text(); })
+      .then(function(response_text) {
+          client_id1 = response_text.substr(17, 36);
+          assert_equals(
+            response_text.substr(0, 15),
+            'Client ID Found',
+            'Service Worker should respond to fetch with a client id');
+          return frame.contentWindow.fetch('resources/other.html?clientId');
+        })
+      .then(function(response) { return response.text(); })
+      .then(function(response_text) {
+          client_id2 = response_text.substr(17, 36);
+          assert_equals(
+            client_id1,
+            client_id2,
+            'Service Worker should respond to another fetch from the same ' +
+            'client with the same client id');
+          frame.remove();
+          return service_worker_unregister_and_done(t, scope);
+        })
+      .catch(unreached_rejection(t));
+  }, 'Service Worker responds to fetch event with a client id');
+
+async_test(function(t) {
     var scope = 'resources/simple.html?ignore';
     service_worker_unregister_and_register(t, worker, scope)
       .then(function(reg) {
@@ -155,8 +196,9 @@
         })
       .then(function(frame) {
           assert_equals(frame.contentDocument.body.textContent,
-                        'POST:testName1=testValue1&testName2=testValue2');
-          document.body.removeChild(frame);
+                        'POST:application/x-www-form-urlencoded:' +
+                        'testName1=testValue1&testName2=testValue2');
+          frame.remove();
           return service_worker_unregister_and_done(t, scope);
         })
       .catch(unreached_rejection(t));
@@ -172,15 +214,7 @@
       .then(function(frame) {
           assert_equals(
             frame.contentDocument.body.textContent,
-            '(0)',
-            'Response should be the argument of the first respondWith() call.');
-          frame.remove();
-          return with_iframe(scope);
-        })
-      .then(function(frame) {
-          assert_equals(
-            frame.contentDocument.body.textContent,
-            '(0)(1)[InvalidStateError](2)[InvalidStateError](0)',
+            '(0)(1)[InvalidStateError](2)[InvalidStateError]',
             'Multiple calls of respondWith must throw InvalidStateErrors.');
           frame.remove();
           return service_worker_unregister_and_done(t, scope);
@@ -190,6 +224,7 @@
 
 async_test(function(t) {
     var scope = 'resources/simple.html?used-check';
+    var first_frame;
     service_worker_unregister_and_register(t, worker, scope)
       .then(function(reg) {
           return wait_for_state(t, reg.installing, 'activated');
@@ -199,7 +234,7 @@
           assert_equals(frame.contentDocument.body.textContent,
                         'Here\'s an other html file.\n',
                         'Response should come from fetched other file');
-          frame.remove();
+          first_frame = frame;
           return with_iframe(scope);
         })
       .then(function(frame) {
@@ -211,6 +246,7 @@
             frame.contentDocument.body.textContent,
             'bodyUsed: true',
             'event.respondWith must set the used flag.');
+          first_frame.remove();
           frame.remove();
           return service_worker_unregister_and_done(t, scope);
         })
diff --git a/third_party/WebKit/LayoutTests/http/tests/serviceworker/resources/fetch-event-test-worker.js b/third_party/WebKit/LayoutTests/http/tests/serviceworker/resources/fetch-event-test-worker.js
index fbcc66fb..1443681 100644
--- a/third_party/WebKit/LayoutTests/http/tests/serviceworker/resources/fetch-event-test-worker.js
+++ b/third_party/WebKit/LayoutTests/http/tests/serviceworker/resources/fetch-event-test-worker.js
@@ -11,6 +11,16 @@
     ['Referrer: ' + event.request.referrer])));
 }
 
+function handleClientId(event) {
+  var body;
+  if (event.clientId !== null) {
+    body = 'Client ID Found: ' + event.clientId;
+  } else {
+    body = 'Client ID Not Found';
+  }
+  event.respondWith(new Response(body));
+}
+
 function handleNullBody(event) {
   event.respondWith(new Response());
 }
@@ -23,18 +33,23 @@
   event.respondWith(new Promise(function(resolve) {
       event.request.text()
         .then(function(result) {
-            resolve(new Response(event.request.method + ':' + result));
+            resolve(new Response(event.request.method + ':' +
+                                 event.request.headers.get('Content-Type') + ':' +
+                                 result));
           });
     }));
 }
 
-var logForMultipleRespondWith = '';
-
 function handleMultipleRespondWith(event) {
+  var logForMultipleRespondWith = '';
   for (var i = 0; i < 3; ++i) {
     logForMultipleRespondWith += '(' + i + ')';
     try {
-      event.respondWith(new Response(logForMultipleRespondWith));
+      event.respondWith(new Promise(function(resolve) {
+        setTimeout(function() {
+          resolve(new Response(logForMultipleRespondWith));
+        }, 0);
+      }));
     } catch (e) {
       logForMultipleRespondWith += '[' + e.name + ']';
     }
@@ -61,6 +76,7 @@
       { pattern: '?string', fn: handleString },
       { pattern: '?blob', fn: handleBlob },
       { pattern: '?referrer', fn: handleReferrer },
+      { pattern: '?clientId', fn: handleClientId },
       { pattern: '?ignore', fn: function() {} },
       { pattern: '?null', fn: handleNullBody },
       { pattern: '?fetch', fn: handleFetch },
diff --git a/third_party/WebKit/LayoutTests/http/tests/serviceworker/resources/interfaces-worker.js b/third_party/WebKit/LayoutTests/http/tests/serviceworker/resources/interfaces-worker.js
index 67d9918..f74f7d9 100644
--- a/third_party/WebKit/LayoutTests/http/tests/serviceworker/resources/interfaces-worker.js
+++ b/third_party/WebKit/LayoutTests/http/tests/serviceworker/resources/interfaces-worker.js
@@ -72,29 +72,47 @@
 
 test(function() {
     assert_equals(
-      new ExtendableEvent('ExtendableEvent').type,
-      'ExtendableEvent', 'Type of ExtendableEvent should be ExtendableEvent');
-    assert_equals(
-      new FetchEvent('FetchEvent').type,
-      'FetchEvent', 'Type of FetchEvent should be FetchEvent');
-    assert_equals(
-      new FetchEvent('FetchEvent').cancelable,
-      false, 'Default FetchEvent.cancelable should be false');
-    assert_equals(
-      new FetchEvent('FetchEvent').bubbles,
-      false, 'Default FetchEvent.bubbles should be false');
-    assert_equals(
-      new FetchEvent('FetchEvent').isReload,
-      false, 'Default FetchEvent.isReload should be false');
-    assert_equals(
-      new FetchEvent('FetchEvent', {cancelable: false}).cancelable,
-      false, 'FetchEvent.cancelable should be false');
-    assert_equals(
-      new FetchEvent('FetchEvent', {isReload : true}).isReload, true,
-      'FetchEvent.isReload with option {isReload : true} should be true');
+        new ExtendableEvent('ExtendableEvent').type,
+        'ExtendableEvent', 'Type of ExtendableEvent should be ExtendableEvent');
     var req = new Request('https://www.example.com/', {method: 'POST'});
     assert_equals(
-      new FetchEvent('FetchEvent', {request: req, isReload: true}).request.url,
-      'https://www.example.com/',
-      'FetchEvent.request.url should return the value it was initialized to');
+        new FetchEvent('FetchEvent', {request: req}).type,
+        'FetchEvent', 'Type of FetchEvent should be FetchEvent');
+    assert_equals(
+        new FetchEvent('FetchEvent', {request: req}).cancelable,
+        false, 'Default FetchEvent.cancelable should be false');
+    assert_equals(
+        new FetchEvent('FetchEvent', {request: req}).bubbles,
+        false, 'Default FetchEvent.bubbles should be false');
+    assert_equals(
+        new FetchEvent('FetchEvent', {request: req}).clientId,
+        null, 'Default FetchEvent.clientId should be null');
+    assert_equals(
+        new FetchEvent('FetchEvent', {request: req}).isReload,
+        false, 'Default FetchEvent.isReload should be false');
+    assert_equals(
+        new FetchEvent(
+            'FetchEvent', {request: req, cancelable: false}).cancelable,
+            false, 'FetchEvent.cancelable should be false');
+    assert_equals(
+        new FetchEvent(
+            'FetchEvent',
+            {request: req,
+             clientId: '006e6aae-cfd4-4331-bea8-fbae364703cf'}).clientId,
+            '006e6aae-cfd4-4331-bea8-fbae364703cf',
+            'FetchEvent.clientId with option {clientId: string} should be ' +
+                'the value of string');
+    assert_equals(
+        new FetchEvent(
+            'FetchEvent',
+            {request: req, isReload: true}).isReload,
+            true,
+            'FetchEvent.isReload with option {isReload: true} should be true');
+    assert_equals(
+        new FetchEvent(
+            'FetchEvent',
+            {request: req, isReload: true}).request.url,
+            'https://www.example.com/',
+            'FetchEvent.request.url should return the value it was ' +
+                'initialized to');
   }, 'Event constructors');
diff --git a/third_party/WebKit/LayoutTests/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt b/third_party/WebKit/LayoutTests/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt
index 25ff8ef..a68bf70 100644
--- a/third_party/WebKit/LayoutTests/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt
@@ -184,6 +184,7 @@
     method constructor
     method waitUntil
 interface FetchEvent : ExtendableEvent
+    getter clientId
     getter isReload
     getter request
     method constructor
diff --git a/third_party/WebKit/LayoutTests/virtual/stable/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt b/third_party/WebKit/LayoutTests/virtual/stable/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt
index 574757f..1dc4a68 100644
--- a/third_party/WebKit/LayoutTests/virtual/stable/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt
+++ b/third_party/WebKit/LayoutTests/virtual/stable/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt
@@ -165,6 +165,7 @@
     method constructor
     method waitUntil
 interface FetchEvent : ExtendableEvent
+    getter clientId
     getter isReload
     getter request
     method constructor
diff --git a/third_party/WebKit/Source/build/scripts/templates/StylePropertyShorthand.h.tmpl b/third_party/WebKit/Source/build/scripts/templates/StylePropertyShorthand.h.tmpl
index ef65b74..0549484 100644
--- a/third_party/WebKit/Source/build/scripts/templates/StylePropertyShorthand.h.tmpl
+++ b/third_party/WebKit/Source/build/scripts/templates/StylePropertyShorthand.h.tmpl
@@ -32,7 +32,6 @@
 public:
     StylePropertyShorthand()
         : m_properties(0)
-        , m_propertiesForInitialization(0)
         , m_length(0)
         , m_shorthandID(CSSPropertyInvalid)
     {
@@ -40,28 +39,17 @@
 
     StylePropertyShorthand(CSSPropertyID id, const CSSPropertyID* properties, unsigned numProperties)
         : m_properties(properties)
-        , m_propertiesForInitialization(0)
-        , m_length(numProperties)
-        , m_shorthandID(id)
-    {
-    }
-
-    StylePropertyShorthand(CSSPropertyID id, const CSSPropertyID* properties, const StylePropertyShorthand** propertiesForInitialization, unsigned numProperties)
-        : m_properties(properties)
-        , m_propertiesForInitialization(propertiesForInitialization)
         , m_length(numProperties)
         , m_shorthandID(id)
     {
     }
 
     const CSSPropertyID* properties() const { return m_properties; }
-    const StylePropertyShorthand** propertiesForInitialization() const { return m_propertiesForInitialization; }
     unsigned length() const { return m_length; }
     CSSPropertyID id() const { return m_shorthandID; }
 
 private:
     const CSSPropertyID* m_properties;
-    const StylePropertyShorthand** m_propertiesForInitialization;
     unsigned m_length;
     CSSPropertyID m_shorthandID;
 };
diff --git a/third_party/WebKit/Source/core/animation/CSSPathInterpolationType.cpp b/third_party/WebKit/Source/core/animation/CSSPathInterpolationType.cpp
new file mode 100644
index 0000000..02997229
--- /dev/null
+++ b/third_party/WebKit/Source/core/animation/CSSPathInterpolationType.cpp
@@ -0,0 +1,81 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "core/animation/CSSPathInterpolationType.h"
+
+#include "core/animation/PathInterpolationFunctions.h"
+#include "core/css/CSSPathValue.h"
+#include "core/css/resolver/StyleResolverState.h"
+
+namespace blink {
+
+void CSSPathInterpolationType::apply(const InterpolableValue& interpolableValue, const NonInterpolableValue* nonInterpolableValue, InterpolationEnvironment& environment) const
+{
+    ASSERT(cssProperty() == CSSPropertyD);
+    environment.state().style()->setD(StylePath::create(PathInterpolationFunctions::appliedValue(interpolableValue, nonInterpolableValue)));
+}
+
+void CSSPathInterpolationType::composite(UnderlyingValue& underlyingValue, double underlyingFraction, const InterpolationValue& value) const
+{
+    PathInterpolationFunctions::composite(underlyingValue, underlyingFraction, value);
+}
+
+PassOwnPtr<InterpolationValue> CSSPathInterpolationType::maybeConvertNeutral(const UnderlyingValue& underlyingValue, ConversionCheckers& conversionCheckers) const
+{
+    return PathInterpolationFunctions::maybeConvertNeutral(*this, underlyingValue, conversionCheckers);
+}
+
+PassOwnPtr<InterpolationValue> CSSPathInterpolationType::maybeConvertInitial() const
+{
+    return PathInterpolationFunctions::convertValue(*this, CSSPathValue::emptyPathValue()->byteStream());
+}
+
+class ParentPathChecker : public InterpolationType::ConversionChecker {
+public:
+    static PassOwnPtr<ParentPathChecker> create(const InterpolationType& type, PassRefPtr<StylePath> stylePath)
+    {
+        return adoptPtr(new ParentPathChecker(type, stylePath));
+    }
+
+private:
+    ParentPathChecker(const InterpolationType& type, PassRefPtr<StylePath> stylePath)
+        : ConversionChecker(type)
+        , m_stylePath(stylePath)
+    { }
+
+    bool isValid(const InterpolationEnvironment& environment, const UnderlyingValue&) const final
+    {
+        return environment.state().parentStyle()->svgStyle().d() == m_stylePath.get();
+    }
+
+    const RefPtr<StylePath> m_stylePath;
+};
+
+PassOwnPtr<InterpolationValue> CSSPathInterpolationType::maybeConvertInherit(const StyleResolverState& state, ConversionCheckers& conversionCheckers) const
+{
+    ASSERT(cssProperty() == CSSPropertyD);
+    if (!state.parentStyle())
+        return nullptr;
+
+    conversionCheckers.append(ParentPathChecker::create(*this, state.parentStyle()->svgStyle().d()));
+    return PathInterpolationFunctions::convertValue(*this, state.parentStyle()->svgStyle().d()->byteStream());
+}
+
+PassOwnPtr<InterpolationValue> CSSPathInterpolationType::maybeConvertValue(const CSSValue& value, const StyleResolverState& state, ConversionCheckers& conversionCheckers) const
+{
+    return PathInterpolationFunctions::convertValue(*this, toCSSPathValue(value).byteStream());
+}
+
+PassOwnPtr<InterpolationValue> CSSPathInterpolationType::maybeConvertUnderlyingValue(const InterpolationEnvironment& environment) const
+{
+    ASSERT(cssProperty() == CSSPropertyD);
+    return PathInterpolationFunctions::convertValue(*this, environment.state().style()->svgStyle().d()->byteStream());
+}
+
+PassOwnPtr<PairwisePrimitiveInterpolation> CSSPathInterpolationType::mergeSingleConversions(InterpolationValue& startValue, InterpolationValue& endValue) const
+{
+    return PathInterpolationFunctions::mergeSingleConversions(*this, startValue, endValue);
+}
+
+} // namespace blink
diff --git a/third_party/WebKit/Source/core/animation/CSSPathInterpolationType.h b/third_party/WebKit/Source/core/animation/CSSPathInterpolationType.h
new file mode 100644
index 0000000..e9f2324
--- /dev/null
+++ b/third_party/WebKit/Source/core/animation/CSSPathInterpolationType.h
@@ -0,0 +1,32 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CSSPathInterpolationType_h
+#define CSSPathInterpolationType_h
+
+#include "core/animation/CSSInterpolationType.h"
+
+namespace blink {
+
+class CSSPathInterpolationType : public CSSInterpolationType {
+public:
+    CSSPathInterpolationType(CSSPropertyID property)
+        : CSSInterpolationType(property)
+    { }
+
+    void apply(const InterpolableValue&, const NonInterpolableValue*, InterpolationEnvironment&) const final;
+    void composite(UnderlyingValue&, double underlyingFraction, const InterpolationValue&) const final;
+
+protected:
+    PassOwnPtr<InterpolationValue> maybeConvertNeutral(const UnderlyingValue&, ConversionCheckers&) const final;
+    PassOwnPtr<InterpolationValue> maybeConvertInitial() const final;
+    PassOwnPtr<InterpolationValue> maybeConvertInherit(const StyleResolverState&, ConversionCheckers&) const final;
+    PassOwnPtr<InterpolationValue> maybeConvertValue(const CSSValue&, const StyleResolverState&, ConversionCheckers&) const final;
+    PassOwnPtr<InterpolationValue> maybeConvertUnderlyingValue(const InterpolationEnvironment&) const final;
+    PassOwnPtr<PairwisePrimitiveInterpolation> mergeSingleConversions(InterpolationValue& startValue, InterpolationValue& endValue) const final;
+};
+
+} // namespace blink
+
+#endif // CSSPathInterpolationType_h
diff --git a/third_party/WebKit/Source/core/animation/PathInterpolationFunctions.cpp b/third_party/WebKit/Source/core/animation/PathInterpolationFunctions.cpp
new file mode 100644
index 0000000..92a837b
--- /dev/null
+++ b/third_party/WebKit/Source/core/animation/PathInterpolationFunctions.cpp
@@ -0,0 +1,167 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "core/animation/PathInterpolationFunctions.h"
+
+#include "core/animation/InterpolatedSVGPathSource.h"
+#include "core/animation/InterpolationEnvironment.h"
+#include "core/animation/SVGPathSegInterpolationFunctions.h"
+#include "core/css/CSSPathValue.h"
+#include "core/svg/SVGPath.h"
+#include "core/svg/SVGPathByteStreamBuilder.h"
+#include "core/svg/SVGPathByteStreamSource.h"
+#include "core/svg/SVGPathParser.h"
+
+namespace blink {
+
+class SVGPathNonInterpolableValue : public NonInterpolableValue {
+public:
+    virtual ~SVGPathNonInterpolableValue() {}
+
+    static PassRefPtr<SVGPathNonInterpolableValue> create(Vector<SVGPathSegType>& pathSegTypes)
+    {
+        return adoptRef(new SVGPathNonInterpolableValue(pathSegTypes));
+    }
+
+    const Vector<SVGPathSegType>& pathSegTypes() const { return m_pathSegTypes; }
+
+    DECLARE_NON_INTERPOLABLE_VALUE_TYPE();
+
+private:
+    SVGPathNonInterpolableValue(Vector<SVGPathSegType>& pathSegTypes)
+    {
+        m_pathSegTypes.swap(pathSegTypes);
+    }
+
+    Vector<SVGPathSegType> m_pathSegTypes;
+};
+
+DEFINE_NON_INTERPOLABLE_VALUE_TYPE(SVGPathNonInterpolableValue);
+DEFINE_NON_INTERPOLABLE_VALUE_TYPE_CASTS(SVGPathNonInterpolableValue);
+
+enum PathComponentIndex {
+    PathArgsIndex,
+    PathNeutralIndex,
+    PathComponentIndexCount,
+};
+
+PassOwnPtr<InterpolationValue> PathInterpolationFunctions::convertValue(const InterpolationType& type, const SVGPathByteStream& byteStream)
+{
+    SVGPathByteStreamSource pathSource(byteStream);
+    size_t length = 0;
+    PathCoordinates currentCoordinates;
+    Vector<OwnPtr<InterpolableValue>> interpolablePathSegs;
+    Vector<SVGPathSegType> pathSegTypes;
+
+    while (pathSource.hasMoreData()) {
+        const PathSegmentData segment = pathSource.parseSegment();
+        interpolablePathSegs.append(SVGPathSegInterpolationFunctions::consumePathSeg(segment, currentCoordinates));
+        pathSegTypes.append(segment.command);
+        length++;
+    }
+
+    OwnPtr<InterpolableList> pathArgs = InterpolableList::create(length);
+    for (size_t i = 0; i < interpolablePathSegs.size(); i++)
+        pathArgs->set(i, interpolablePathSegs[i].release());
+
+    OwnPtr<InterpolableList> result = InterpolableList::create(PathComponentIndexCount);
+    result->set(PathArgsIndex, pathArgs.release());
+    result->set(PathNeutralIndex, InterpolableNumber::create(0));
+
+    return InterpolationValue::create(type, result.release(), SVGPathNonInterpolableValue::create(pathSegTypes));
+}
+
+class UnderlyingPathSegTypesChecker : public InterpolationType::ConversionChecker {
+public:
+    ~UnderlyingPathSegTypesChecker() final {}
+
+    static PassOwnPtr<UnderlyingPathSegTypesChecker> create(const InterpolationType& type, const UnderlyingValue& underlyingValue)
+    {
+        return adoptPtr(new UnderlyingPathSegTypesChecker(type, getPathSegTypes(underlyingValue)));
+    }
+
+private:
+    UnderlyingPathSegTypesChecker(const InterpolationType& type, const Vector<SVGPathSegType>& pathSegTypes)
+        : ConversionChecker(type)
+        , m_pathSegTypes(pathSegTypes)
+    { }
+
+    static const Vector<SVGPathSegType>& getPathSegTypes(const UnderlyingValue& underlyingValue)
+    {
+        return toSVGPathNonInterpolableValue(underlyingValue->nonInterpolableValue())->pathSegTypes();
+    }
+
+    bool isValid(const InterpolationEnvironment&, const UnderlyingValue& underlyingValue) const final
+    {
+        return m_pathSegTypes == getPathSegTypes(underlyingValue);
+    }
+
+    Vector<SVGPathSegType> m_pathSegTypes;
+};
+
+PassOwnPtr<InterpolationValue> PathInterpolationFunctions::maybeConvertNeutral(const InterpolationType& type, const UnderlyingValue& underlyingValue, InterpolationType::ConversionCheckers& conversionCheckers)
+{
+    conversionCheckers.append(UnderlyingPathSegTypesChecker::create(type, underlyingValue));
+    OwnPtr<InterpolableList> result = InterpolableList::create(PathComponentIndexCount);
+    result->set(PathArgsIndex, toInterpolableList(underlyingValue->interpolableValue()).get(PathArgsIndex)->cloneAndZero());
+    result->set(PathNeutralIndex, InterpolableNumber::create(1));
+    return InterpolationValue::create(type, result.release(),
+        const_cast<NonInterpolableValue*>(underlyingValue->nonInterpolableValue())); // Take ref.
+}
+
+static bool pathSegTypesMatch(const Vector<SVGPathSegType>& a, const Vector<SVGPathSegType>& b)
+{
+    if (a.size() != b.size())
+        return false;
+
+    for (size_t i = 0; i < a.size(); i++) {
+        if (toAbsolutePathSegType(a[i]) != toAbsolutePathSegType(b[i]))
+            return false;
+    }
+
+    return true;
+}
+
+PassOwnPtr<PairwisePrimitiveInterpolation> PathInterpolationFunctions::mergeSingleConversions(const InterpolationType& type, InterpolationValue& startValue, InterpolationValue& endValue)
+{
+    const Vector<SVGPathSegType>& startTypes = toSVGPathNonInterpolableValue(startValue.nonInterpolableValue())->pathSegTypes();
+    const Vector<SVGPathSegType>& endTypes = toSVGPathNonInterpolableValue(endValue.nonInterpolableValue())->pathSegTypes();
+    if (!pathSegTypesMatch(startTypes, endTypes))
+        return nullptr;
+
+    return PairwisePrimitiveInterpolation::create(type,
+        startValue.mutableComponent().interpolableValue.release(),
+        endValue.mutableComponent().interpolableValue.release(),
+        const_cast<NonInterpolableValue*>(endValue.nonInterpolableValue())); // Take ref.
+}
+
+void PathInterpolationFunctions::composite(UnderlyingValue& underlyingValue, double underlyingFraction, const InterpolationValue& value)
+{
+    const InterpolableList& list = toInterpolableList(value.interpolableValue());
+    double neutralComponent = toInterpolableNumber(list.get(PathNeutralIndex))->value();
+
+    if (neutralComponent == 0) {
+        underlyingValue.set(&value);
+        return;
+    }
+
+    ASSERT(pathSegTypesMatch(
+        toSVGPathNonInterpolableValue(underlyingValue->nonInterpolableValue())->pathSegTypes(),
+        toSVGPathNonInterpolableValue(value.nonInterpolableValue())->pathSegTypes()));
+    underlyingValue.mutableComponent().interpolableValue->scaleAndAdd(neutralComponent, value.interpolableValue());
+    underlyingValue.mutableComponent().nonInterpolableValue = const_cast<NonInterpolableValue*>(value.nonInterpolableValue()); // Take ref.
+}
+
+PassRefPtr<SVGPathByteStream> PathInterpolationFunctions::appliedValue(const InterpolableValue& interpolableValue, const NonInterpolableValue* nonInterpolableValue)
+{
+    RefPtr<SVGPathByteStream> pathByteStream = SVGPathByteStream::create();
+    InterpolatedSVGPathSource source(
+        toInterpolableList(*toInterpolableList(interpolableValue).get(PathArgsIndex)),
+        toSVGPathNonInterpolableValue(nonInterpolableValue)->pathSegTypes());
+    SVGPathByteStreamBuilder builder(*pathByteStream);
+    SVGPathParser(&source, &builder).parsePathDataFromSource(UnalteredParsing, false);
+    return pathByteStream.release();
+}
+
+} // namespace blink
diff --git a/third_party/WebKit/Source/core/animation/PathInterpolationFunctions.h b/third_party/WebKit/Source/core/animation/PathInterpolationFunctions.h
new file mode 100644
index 0000000..ef28b560
--- /dev/null
+++ b/third_party/WebKit/Source/core/animation/PathInterpolationFunctions.h
@@ -0,0 +1,28 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef PathInterpolationFunctions_h
+#define PathInterpolationFunctions_h
+
+#include "core/animation/InterpolationType.h"
+#include "core/svg/SVGPathByteStream.h"
+
+namespace blink {
+
+class PathInterpolationFunctions {
+public:
+    static PassRefPtr<SVGPathByteStream> appliedValue(const InterpolableValue&, const NonInterpolableValue*);
+
+    static void composite(UnderlyingValue&, double underlyingFraction, const InterpolationValue&);
+
+    static PassOwnPtr<InterpolationValue> convertValue(const InterpolationType&, const SVGPathByteStream&);
+
+    static PassOwnPtr<InterpolationValue> maybeConvertNeutral(const InterpolationType&, const UnderlyingValue&, InterpolationType::ConversionCheckers&);
+
+    static PassOwnPtr<PairwisePrimitiveInterpolation> mergeSingleConversions(const InterpolationType&, InterpolationValue& startValue, InterpolationValue& endValue);
+};
+
+} // namespace blink
+
+#endif // PathInterpolationFunctions_h
diff --git a/third_party/WebKit/Source/core/animation/SVGPathInterpolationType.cpp b/third_party/WebKit/Source/core/animation/SVGPathInterpolationType.cpp
index 9525f660..d1afb30a 100644
--- a/third_party/WebKit/Source/core/animation/SVGPathInterpolationType.cpp
+++ b/third_party/WebKit/Source/core/animation/SVGPathInterpolationType.cpp
@@ -4,166 +4,38 @@
 
 #include "core/animation/SVGPathInterpolationType.h"
 
-#include "core/animation/InterpolatedSVGPathSource.h"
-#include "core/animation/InterpolationEnvironment.h"
-#include "core/animation/SVGPathSegInterpolationFunctions.h"
+#include "core/animation/PathInterpolationFunctions.h"
+
 #include "core/svg/SVGPath.h"
-#include "core/svg/SVGPathByteStreamBuilder.h"
-#include "core/svg/SVGPathByteStreamSource.h"
-#include "core/svg/SVGPathParser.h"
 
 namespace blink {
 
-class SVGPathNonInterpolableValue : public NonInterpolableValue {
-public:
-    virtual ~SVGPathNonInterpolableValue() {}
-
-    static PassRefPtr<SVGPathNonInterpolableValue> create(Vector<SVGPathSegType>& pathSegTypes)
-    {
-        return adoptRef(new SVGPathNonInterpolableValue(pathSegTypes));
-    }
-
-    const Vector<SVGPathSegType>& pathSegTypes() const { return m_pathSegTypes; }
-
-    DECLARE_NON_INTERPOLABLE_VALUE_TYPE();
-
-private:
-    SVGPathNonInterpolableValue(Vector<SVGPathSegType>& pathSegTypes)
-    {
-        m_pathSegTypes.swap(pathSegTypes);
-    }
-
-    Vector<SVGPathSegType> m_pathSegTypes;
-};
-
-DEFINE_NON_INTERPOLABLE_VALUE_TYPE(SVGPathNonInterpolableValue);
-DEFINE_NON_INTERPOLABLE_VALUE_TYPE_CASTS(SVGPathNonInterpolableValue);
-
-enum PathComponentIndex {
-    PathArgsIndex,
-    PathNeutralIndex,
-    PathComponentIndexCount,
-};
-
 PassOwnPtr<InterpolationValue> SVGPathInterpolationType::maybeConvertSVGValue(const SVGPropertyBase& svgValue) const
 {
     if (svgValue.type() != AnimatedPath)
         return nullptr;
 
-    SVGPathByteStreamSource pathSource(toSVGPath(svgValue).byteStream());
-    size_t length = 0;
-    PathCoordinates currentCoordinates;
-    Vector<OwnPtr<InterpolableValue>> interpolablePathSegs;
-    Vector<SVGPathSegType> pathSegTypes;
-
-    while (pathSource.hasMoreData()) {
-        const PathSegmentData segment = pathSource.parseSegment();
-        interpolablePathSegs.append(SVGPathSegInterpolationFunctions::consumePathSeg(segment, currentCoordinates));
-        pathSegTypes.append(segment.command);
-        length++;
-    }
-
-    OwnPtr<InterpolableList> pathArgs = InterpolableList::create(length);
-    for (size_t i = 0; i < interpolablePathSegs.size(); i++)
-        pathArgs->set(i, interpolablePathSegs[i].release());
-
-    OwnPtr<InterpolableList> result = InterpolableList::create(PathComponentIndexCount);
-    result->set(PathArgsIndex, pathArgs.release());
-    result->set(PathNeutralIndex, InterpolableNumber::create(0));
-
-    return InterpolationValue::create(*this, result.release(), SVGPathNonInterpolableValue::create(pathSegTypes));
+    return PathInterpolationFunctions::convertValue(*this, toSVGPath(svgValue).byteStream());
 }
 
-class UnderlyingPathSegTypesChecker : public InterpolationType::ConversionChecker {
-public:
-    ~UnderlyingPathSegTypesChecker() final {}
-
-    static PassOwnPtr<UnderlyingPathSegTypesChecker> create(const InterpolationType& type, const UnderlyingValue& underlyingValue)
-    {
-        return adoptPtr(new UnderlyingPathSegTypesChecker(type, getPathSegTypes(underlyingValue)));
-    }
-
-private:
-    UnderlyingPathSegTypesChecker(const InterpolationType& type, const Vector<SVGPathSegType>& pathSegTypes)
-        : ConversionChecker(type)
-        , m_pathSegTypes(pathSegTypes)
-    { }
-
-    static const Vector<SVGPathSegType>& getPathSegTypes(const UnderlyingValue& underlyingValue)
-    {
-        return toSVGPathNonInterpolableValue(underlyingValue->nonInterpolableValue())->pathSegTypes();
-    }
-
-    bool isValid(const InterpolationEnvironment&, const UnderlyingValue& underlyingValue) const final
-    {
-        return m_pathSegTypes == getPathSegTypes(underlyingValue);
-    }
-
-    Vector<SVGPathSegType> m_pathSegTypes;
-};
-
 PassOwnPtr<InterpolationValue> SVGPathInterpolationType::maybeConvertNeutral(const UnderlyingValue& underlyingValue, ConversionCheckers& conversionCheckers) const
 {
-    conversionCheckers.append(UnderlyingPathSegTypesChecker::create(*this, underlyingValue));
-    OwnPtr<InterpolableList> result = InterpolableList::create(PathComponentIndexCount);
-    result->set(PathArgsIndex, toInterpolableList(underlyingValue->interpolableValue()).get(PathArgsIndex)->cloneAndZero());
-    result->set(PathNeutralIndex, InterpolableNumber::create(1));
-    return InterpolationValue::create(*this, result.release(),
-        const_cast<NonInterpolableValue*>(underlyingValue->nonInterpolableValue())); // Take ref.
-}
-
-static bool pathSegTypesMatch(const Vector<SVGPathSegType>& a, const Vector<SVGPathSegType>& b)
-{
-    if (a.size() != b.size())
-        return false;
-
-    for (size_t i = 0; i < a.size(); i++) {
-        if (toAbsolutePathSegType(a[i]) != toAbsolutePathSegType(b[i]))
-            return false;
-    }
-
-    return true;
+    return PathInterpolationFunctions::maybeConvertNeutral(*this, underlyingValue, conversionCheckers);
 }
 
 PassOwnPtr<PairwisePrimitiveInterpolation> SVGPathInterpolationType::mergeSingleConversions(InterpolationValue& startValue, InterpolationValue& endValue) const
 {
-    const Vector<SVGPathSegType>& startTypes = toSVGPathNonInterpolableValue(startValue.nonInterpolableValue())->pathSegTypes();
-    const Vector<SVGPathSegType>& endTypes = toSVGPathNonInterpolableValue(endValue.nonInterpolableValue())->pathSegTypes();
-    if (!pathSegTypesMatch(startTypes, endTypes))
-        return nullptr;
-
-    return PairwisePrimitiveInterpolation::create(*this,
-        startValue.mutableComponent().interpolableValue.release(),
-        endValue.mutableComponent().interpolableValue.release(),
-        const_cast<NonInterpolableValue*>(endValue.nonInterpolableValue())); // Take ref.
+    return PathInterpolationFunctions::mergeSingleConversions(*this, startValue, endValue);
 }
 
 void SVGPathInterpolationType::composite(UnderlyingValue& underlyingValue, double underlyingFraction, const InterpolationValue& value) const
 {
-    const InterpolableList& list = toInterpolableList(value.interpolableValue());
-    double neutralComponent = toInterpolableNumber(list.get(PathNeutralIndex))->value();
-
-    if (neutralComponent == 0) {
-        underlyingValue.set(&value);
-        return;
-    }
-
-    ASSERT(pathSegTypesMatch(
-        toSVGPathNonInterpolableValue(underlyingValue->nonInterpolableValue())->pathSegTypes(),
-        toSVGPathNonInterpolableValue(value.nonInterpolableValue())->pathSegTypes()));
-    underlyingValue.mutableComponent().interpolableValue->scaleAndAdd(neutralComponent, value.interpolableValue());
-    underlyingValue.mutableComponent().nonInterpolableValue = const_cast<NonInterpolableValue*>(value.nonInterpolableValue()); // Take ref.
+    PathInterpolationFunctions::composite(underlyingValue, underlyingFraction, value);
 }
 
 PassRefPtrWillBeRawPtr<SVGPropertyBase> SVGPathInterpolationType::appliedSVGValue(const InterpolableValue& interpolableValue, const NonInterpolableValue* nonInterpolableValue) const
 {
-    RefPtr<SVGPathByteStream> pathByteStream = SVGPathByteStream::create();
-    InterpolatedSVGPathSource source(
-        toInterpolableList(*toInterpolableList(interpolableValue).get(PathArgsIndex)),
-        toSVGPathNonInterpolableValue(nonInterpolableValue)->pathSegTypes());
-    SVGPathByteStreamBuilder builder(*pathByteStream);
-    SVGPathParser(&source, &builder).parsePathDataFromSource(UnalteredParsing, false);
-    return SVGPath::create(CSSPathValue::create(pathByteStream.release()));
+    return SVGPath::create(CSSPathValue::create(PathInterpolationFunctions::appliedValue(interpolableValue, nonInterpolableValue)));
 }
 
 } // namespace blink
diff --git a/third_party/WebKit/Source/core/animation/StringKeyframe.cpp b/third_party/WebKit/Source/core/animation/StringKeyframe.cpp
index 6d77cde5..990b7f61 100644
--- a/third_party/WebKit/Source/core/animation/StringKeyframe.cpp
+++ b/third_party/WebKit/Source/core/animation/StringKeyframe.cpp
@@ -14,6 +14,7 @@
 #include "core/animation/CSSLengthListInterpolationType.h"
 #include "core/animation/CSSNumberInterpolationType.h"
 #include "core/animation/CSSPaintInterpolationType.h"
+#include "core/animation/CSSPathInterpolationType.h"
 #include "core/animation/CSSShadowListInterpolationType.h"
 #include "core/animation/CSSValueInterpolationType.h"
 #include "core/animation/CSSVisibilityInterpolationType.h"
@@ -261,6 +262,9 @@
         case CSSPropertyStroke:
             applicableTypes->append(adoptPtr(new CSSPaintInterpolationType(cssProperty)));
             break;
+        case CSSPropertyD:
+            applicableTypes->append(adoptPtr(new CSSPathInterpolationType(cssProperty)));
+            break;
         case CSSPropertyBoxShadow:
         case CSSPropertyTextShadow:
             applicableTypes->append(adoptPtr(new CSSShadowListInterpolationType(cssProperty)));
diff --git a/third_party/WebKit/Source/core/core.gypi b/third_party/WebKit/Source/core/core.gypi
index 56599d3..837757e 100644
--- a/third_party/WebKit/Source/core/core.gypi
+++ b/third_party/WebKit/Source/core/core.gypi
@@ -858,6 +858,8 @@
             'animation/CSSNumberInterpolationType.h',
             'animation/CSSPaintInterpolationType.cpp',
             'animation/CSSPaintInterpolationType.h',
+            'animation/CSSPathInterpolationType.cpp',
+            'animation/CSSPathInterpolationType.h',
             'animation/CSSShadowListInterpolationType.cpp',
             'animation/CSSShadowListInterpolationType.h',
             'animation/CSSValueInterpolationType.cpp',
@@ -925,6 +927,8 @@
             'animation/NumberSVGInterpolation.h',
             'animation/PaintPropertyFunctions.cpp',
             'animation/PaintPropertyFunctions.h',
+            'animation/PathInterpolationFunctions.cpp',
+            'animation/PathInterpolationFunctions.h',
             'animation/PrimitiveInterpolation.h',
             'animation/PropertyHandle.cpp',
             'animation/PropertyHandle.h',
diff --git a/third_party/WebKit/Source/core/css/StylePropertyShorthandCustom.cpp b/third_party/WebKit/Source/core/css/StylePropertyShorthandCustom.cpp
index ae85bce..d91cbb3 100644
--- a/third_party/WebKit/Source/core/css/StylePropertyShorthandCustom.cpp
+++ b/third_party/WebKit/Source/core/css/StylePropertyShorthandCustom.cpp
@@ -23,18 +23,6 @@
 
 namespace blink {
 
-const StylePropertyShorthand& borderShorthandForParsing()
-{
-    static const CSSPropertyID borderShorthandProperties[] = { CSSPropertyBorderWidth, CSSPropertyBorderStyle, CSSPropertyBorderColor };
-    static const StylePropertyShorthand* propertiesForInitialization[] = {
-        &borderWidthShorthand(),
-        &borderStyleShorthand(),
-        &borderColorShorthand(),
-    };
-    DEFINE_STATIC_LOCAL(StylePropertyShorthand, borderForParsingLonghands, (CSSPropertyBorder, borderShorthandProperties, propertiesForInitialization, WTF_ARRAY_LENGTH(borderShorthandProperties)));
-    return borderForParsingLonghands;
-}
-
 const StylePropertyShorthand& animationShorthandForParsing()
 {
     // When we parse the animation shorthand we need to look for animation-name
diff --git a/third_party/WebKit/Source/core/css/cssom/CalcLength.idl b/third_party/WebKit/Source/core/css/cssom/CalcLength.idl
index 0a4e860f..79b2d2c 100644
--- a/third_party/WebKit/Source/core/css/cssom/CalcLength.idl
+++ b/third_party/WebKit/Source/core/css/cssom/CalcLength.idl
@@ -5,19 +5,19 @@
     RaisesException=Constructor,
     RuntimeEnabled=CSSTypedOM
 ] interface CalcLength : LengthValue {
-    attribute double? px;
-    attribute double? percent;
-    attribute double? em;
-    attribute double? ex;
-    attribute double? ch;
-    attribute double? rem;
-    attribute double? vw;
-    attribute double? vh;
-    attribute double? vmin;
-    attribute double? vmax;
-    attribute double? cm;
-    attribute double? mm;
-    attribute double? in;
-    attribute double? pc;
-    attribute double? pt;
+    readonly attribute double? px;
+    readonly attribute double? percent;
+    readonly attribute double? em;
+    readonly attribute double? ex;
+    readonly attribute double? ch;
+    readonly attribute double? rem;
+    readonly attribute double? vw;
+    readonly attribute double? vh;
+    readonly attribute double? vmin;
+    readonly attribute double? vmax;
+    readonly attribute double? cm;
+    readonly attribute double? mm;
+    readonly attribute double? in;
+    readonly attribute double? pc;
+    readonly attribute double? pt;
 };
diff --git a/third_party/WebKit/Source/core/css/cssom/StyleCalcLength.h b/third_party/WebKit/Source/core/css/cssom/StyleCalcLength.h
index 1889085..d086926 100644
--- a/third_party/WebKit/Source/core/css/cssom/StyleCalcLength.h
+++ b/third_party/WebKit/Source/core/css/cssom/StyleCalcLength.h
@@ -23,27 +23,26 @@
         return create(length);
     }
 
-#define GETTER_SETTER_MACRO(name, capsName, index) \
-    double name(bool& isNull) { isNull = !has(index); return get(index); } \
-    void set##capsName(double value) { set(value, index); }
+#define GETTER_MACRO(name, index) \
+    double name(bool& isNull) { isNull = !has(index); return get(index); }
 
-    GETTER_SETTER_MACRO(px, Px, LengthUnit::Px)
-    GETTER_SETTER_MACRO(percent, Percent, LengthUnit::Percent)
-    GETTER_SETTER_MACRO(em, Em, LengthUnit::Em)
-    GETTER_SETTER_MACRO(ex, Ex, LengthUnit::Ex)
-    GETTER_SETTER_MACRO(ch, Ch, LengthUnit::Ch)
-    GETTER_SETTER_MACRO(rem, Rem, LengthUnit::Rem)
-    GETTER_SETTER_MACRO(vw, Vw, LengthUnit::Vw)
-    GETTER_SETTER_MACRO(vh, Vh, LengthUnit::Vh)
-    GETTER_SETTER_MACRO(vmin, Vmin, LengthUnit::Vmin)
-    GETTER_SETTER_MACRO(vmax, Vmax, LengthUnit::Vmax)
-    GETTER_SETTER_MACRO(cm, Cm, LengthUnit::Cm)
-    GETTER_SETTER_MACRO(mm, Mm, LengthUnit::Mm)
-    GETTER_SETTER_MACRO(in, In, LengthUnit::In)
-    GETTER_SETTER_MACRO(pc, Pc, LengthUnit::Pc)
-    GETTER_SETTER_MACRO(pt, Pt, LengthUnit::Pt)
+    GETTER_MACRO(px, LengthUnit::Px)
+    GETTER_MACRO(percent, LengthUnit::Percent)
+    GETTER_MACRO(em, LengthUnit::Em)
+    GETTER_MACRO(ex, LengthUnit::Ex)
+    GETTER_MACRO(ch, LengthUnit::Ch)
+    GETTER_MACRO(rem, LengthUnit::Rem)
+    GETTER_MACRO(vw, LengthUnit::Vw)
+    GETTER_MACRO(vh, LengthUnit::Vh)
+    GETTER_MACRO(vmin, LengthUnit::Vmin)
+    GETTER_MACRO(vmax, LengthUnit::Vmax)
+    GETTER_MACRO(cm, LengthUnit::Cm)
+    GETTER_MACRO(mm, LengthUnit::Mm)
+    GETTER_MACRO(in, LengthUnit::In)
+    GETTER_MACRO(pc, LengthUnit::Pc)
+    GETTER_MACRO(pt, LengthUnit::Pt)
 
-#undef GETTER_SETTER_MACRO
+#undef GETTER_MACRO
 
     String cssString() const override;
     PassRefPtrWillBeRawPtr<CSSValue> toCSSValue() const override;
diff --git a/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.cpp b/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.cpp
index 506828c..170c520 100644
--- a/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.cpp
+++ b/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.cpp
@@ -107,21 +107,16 @@
     CSSParserTokenRange originalRange = m_range;
     CSSPropertyID propertyId = resolveCSSPropertyID(unresolvedProperty);
 
-    if (RefPtrWillBeRawPtr<CSSValue> parsedValue = parseSingleValue(unresolvedProperty)) {
-        if (!m_range.atEnd())
-            return false;
-        addProperty(propertyId, parsedValue.release(), important);
-        return true;
-    }
-
-    if (parseShorthand(unresolvedProperty, important))
-        return true;
-
-    CSSParserValueList valueList(m_range);
-    if (valueList.size()) {
-        m_valueList = &valueList;
-        if (parseValue(unresolvedProperty, important))
+    if (isShorthandProperty(propertyId)) {
+        if (parseShorthand(unresolvedProperty, important))
             return true;
+    } else {
+        if (RefPtrWillBeRawPtr<CSSValue> parsedValue = parseSingleValue(unresolvedProperty)) {
+            if (!m_range.atEnd())
+                return false;
+            addProperty(propertyId, parsedValue.release(), important);
+            return true;
+        }
     }
 
     if (RuntimeEnabledFeatures::cssVariablesEnabled() && CSSVariableParser::containsValidVariableReferences(originalRange)) {
@@ -2011,27 +2006,27 @@
     return consumeColor(range, cssParserMode);
 }
 
-static PassRefPtrWillBeRawPtr<CSSPrimitiveValue> consumeLineWidth(CSSParserTokenRange& range, CSSParserMode cssParserMode)
+static PassRefPtrWillBeRawPtr<CSSPrimitiveValue> consumeLineWidth(CSSParserTokenRange& range, CSSParserMode cssParserMode, UnitlessQuirk unitless)
 {
     CSSValueID id = range.peek().id();
     if (id == CSSValueThin || id == CSSValueMedium || id == CSSValueThick)
         return consumeIdent(range);
-    return consumeLength(range, cssParserMode, ValueRangeNonNegative);
+    return consumeLength(range, cssParserMode, ValueRangeNonNegative, unitless);
 }
 
-static PassRefPtrWillBeRawPtr<CSSPrimitiveValue> consumeBorderWidth(CSSParserTokenRange& range, CSSParserMode cssParserMode)
+static PassRefPtrWillBeRawPtr<CSSPrimitiveValue> consumeBorderWidth(CSSParserTokenRange& range, CSSParserMode cssParserMode, UnitlessQuirk unitless)
 {
-    return consumeLineWidth(range, cssParserMode);
+    return consumeLineWidth(range, cssParserMode, unitless);
 }
 
 static PassRefPtrWillBeRawPtr<CSSPrimitiveValue> consumeTextStrokeWidth(CSSParserTokenRange& range, CSSParserMode cssParserMode)
 {
-    return consumeLineWidth(range, cssParserMode);
+    return consumeLineWidth(range, cssParserMode, UnitlessQuirk::Forbid);
 }
 
 static PassRefPtrWillBeRawPtr<CSSPrimitiveValue> consumeColumnRuleWidth(CSSParserTokenRange& range, CSSParserMode cssParserMode)
 {
-    return consumeLineWidth(range, cssParserMode);
+    return consumeLineWidth(range, cssParserMode, UnitlessQuirk::Forbid);
 }
 
 static bool consumeTranslate3d(CSSParserTokenRange& args, CSSParserMode cssParserMode, RefPtrWillBeRawPtr<CSSFunctionValue>& transformValue)
@@ -2952,6 +2947,11 @@
 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseSingleValue(CSSPropertyID unresolvedProperty)
 {
     CSSPropertyID property = resolveCSSPropertyID(unresolvedProperty);
+    if (CSSParserFastPaths::isKeywordPropertyID(property)) {
+        if (!CSSParserFastPaths::isValidKeywordPropertyAndValue(property, m_range.peek().id()))
+            return nullptr;
+        return consumeIdent(m_range);
+    }
     switch (property) {
     case CSSPropertyWillChange:
         return consumeWillChange(m_range);
@@ -3106,7 +3106,24 @@
     case CSSPropertyWebkitBorderEndWidth:
     case CSSPropertyWebkitBorderBeforeWidth:
     case CSSPropertyWebkitBorderAfterWidth:
-        return consumeBorderWidth(m_range, m_context.mode());
+        return consumeBorderWidth(m_range, m_context.mode(), UnitlessQuirk::Forbid);
+    case CSSPropertyBorderBottomColor:
+    case CSSPropertyBorderLeftColor:
+    case CSSPropertyBorderRightColor:
+    case CSSPropertyBorderTopColor: {
+        bool allowQuirkyColors = inQuirksMode()
+            && (m_currentShorthand == CSSPropertyInvalid || m_currentShorthand == CSSPropertyBorderColor);
+        return consumeColor(m_range, m_context.mode(), allowQuirkyColors);
+    }
+    case CSSPropertyBorderBottomWidth:
+    case CSSPropertyBorderLeftWidth:
+    case CSSPropertyBorderRightWidth:
+    case CSSPropertyBorderTopWidth: {
+        bool allowQuirkyLengths = inQuirksMode()
+            && (m_currentShorthand == CSSPropertyInvalid || m_currentShorthand == CSSPropertyBorderWidth);
+        UnitlessQuirk unitless = allowQuirkyLengths ? UnitlessQuirk::Allow : UnitlessQuirk::Forbid;
+        return consumeBorderWidth(m_range, m_context.mode(), unitless);
+    }
     case CSSPropertyZIndex:
         return consumeZIndex(m_range);
     case CSSPropertyTextShadow: // CSS2 property, dropped in CSS2.1, back in CSS3, so treat as CSS3
@@ -3115,6 +3132,9 @@
     case CSSPropertyWebkitFilter:
     case CSSPropertyBackdropFilter:
         return consumeFilter(m_range, m_context.mode());
+    case CSSPropertyTextDecoration:
+        ASSERT(!RuntimeEnabledFeatures::css3TextDecorationsEnabled());
+        // fallthrough
     case CSSPropertyWebkitTextDecorationsInEffect:
     case CSSPropertyTextDecorationLine:
         return consumeTextDecorationLine(m_range);
@@ -3133,7 +3153,7 @@
     case CSSPropertyOutlineOffset:
         return consumeLength(m_range, m_context.mode(), ValueRangeAll);
     case CSSPropertyOutlineWidth:
-        return consumeLineWidth(m_range, m_context.mode());
+        return consumeLineWidth(m_range, m_context.mode(), UnitlessQuirk::Forbid);
     case CSSPropertyTransform:
         return consumeTransform(m_range, m_context.mode(), unresolvedProperty == CSSPropertyAliasWebkitTransform);
     case CSSPropertyWebkitTransformOriginX:
@@ -3219,6 +3239,15 @@
     case CSSPropertyVerticalAlign:
         return consumeVerticalAlign(m_range, m_context.mode());
     default:
+        CSSParserValueList valueList(m_range);
+        if (valueList.size()) {
+            m_valueList = &valueList;
+            if (RefPtrWillBeRawPtr<CSSValue> result = legacyParseValue(unresolvedProperty)) {
+                while (!m_range.atEnd())
+                    m_range.consume();
+                return result.release();
+            }
+        }
         return nullptr;
     }
 }
@@ -3589,13 +3618,7 @@
         for (size_t i = 0; !foundLonghand && i < shorthand.length(); ++i) {
             if (longhands[i])
                 continue;
-            // TODO: parseSingleValue needs to handle fastpath keywords.
-            if (CSSParserFastPaths::isKeywordPropertyID(shorthandProperties[i])) {
-                if (CSSParserFastPaths::isValidKeywordPropertyAndValue(shorthandProperties[i], m_range.peek().id()))
-                    longhands[i] = consumeIdent(m_range);
-            } else {
-                longhands[i] = parseSingleValue(shorthandProperties[i]);
-            }
+            longhands[i] = parseSingleValue(shorthandProperties[i]);
             if (longhands[i])
                 foundLonghand = true;
         }
@@ -3668,6 +3691,40 @@
     return true;
 }
 
+bool CSSPropertyParser::consumeBorder(bool important)
+{
+    RefPtrWillBeRawPtr<CSSValue> width = nullptr;
+    RefPtrWillBeRawPtr<CSSValue> style = nullptr;
+    RefPtrWillBeRawPtr<CSSValue> color = nullptr;
+
+    while (!width || !style || !color) {
+        if (!width && (width = consumeLineWidth(m_range, m_context.mode(), UnitlessQuirk::Forbid)))
+            continue;
+        if (!style && (style = parseSingleValue(CSSPropertyBorderLeftStyle)))
+            continue;
+        if (!color && (color = consumeColor(m_range, m_context.mode())))
+            continue;
+        break;
+    }
+
+    if (!width && !style && !color)
+        return false;
+
+    if (!width)
+        width = cssValuePool().createImplicitInitialValue();
+    if (!style)
+        style = cssValuePool().createImplicitInitialValue();
+    if (!color)
+        color = cssValuePool().createImplicitInitialValue();
+
+    addExpandedPropertyForValue(CSSPropertyBorderWidth, width.release(), important);
+    addExpandedPropertyForValue(CSSPropertyBorderStyle, style.release(), important);
+    addExpandedPropertyForValue(CSSPropertyBorderColor, color.release(), important);
+    addExpandedPropertyForValue(CSSPropertyBorderImage, cssValuePool().createImplicitInitialValue(), important);
+
+    return m_range.atEnd();
+}
+
 bool CSSPropertyParser::consume4Values(const StylePropertyShorthand& shorthand, bool important)
 {
     ASSERT(shorthand.length() == 4);
@@ -3805,19 +3862,9 @@
         return consumeAnimationShorthand(animationShorthandForParsing(), unresolvedProperty == CSSPropertyAliasWebkitAnimation, important);
     case CSSPropertyTransition:
         return consumeAnimationShorthand(transitionShorthandForParsing(), false, important);
-    case CSSPropertyTextDecoration: {
-        // Fall through 'text-decoration-line' parsing if CSS 3 Text Decoration
-        // is disabled to match CSS 2.1 rules for parsing 'text-decoration'.
-        if (RuntimeEnabledFeatures::css3TextDecorationsEnabled())
-            return consumeShorthandGreedily(textDecorationShorthand(), important);
-        // TODO(rwlbuis): investigate if this shorthand hack can be removed.
-        m_currentShorthand = oldShorthand;
-        RefPtrWillBeRawPtr<CSSValue> textDecoration = consumeTextDecorationLine(m_range);
-        if (!textDecoration || !m_range.atEnd())
-            return false;
-        addProperty(CSSPropertyTextDecoration, textDecoration.release(), important);
-        return true;
-    }
+    case CSSPropertyTextDecoration:
+        ASSERT(RuntimeEnabledFeatures::css3TextDecorationsEnabled());
+        return consumeShorthandGreedily(textDecorationShorthand(), important);
     case CSSPropertyMargin:
         return consume4Values(marginShorthand(), important);
     case CSSPropertyPadding:
@@ -3867,9 +3914,29 @@
         addProperty(CSSPropertyBorderBottomLeftRadius, CSSValuePair::create(horizontalRadii[3].release(), verticalRadii[3].release(), CSSValuePair::DropIdenticalValues), important);
         return true;
     }
+    case CSSPropertyBorderColor:
+        return consume4Values(borderColorShorthand(), important);
+    case CSSPropertyBorderStyle:
+        return consume4Values(borderStyleShorthand(), important);
+    case CSSPropertyBorderWidth:
+        return consume4Values(borderWidthShorthand(), important);
+    case CSSPropertyBorderTop:
+        return consumeShorthandGreedily(borderTopShorthand(), important);
+    case CSSPropertyBorderRight:
+        return consumeShorthandGreedily(borderRightShorthand(), important);
+    case CSSPropertyBorderBottom:
+        return consumeShorthandGreedily(borderBottomShorthand(), important);
+    case CSSPropertyBorderLeft:
+        return consumeShorthandGreedily(borderLeftShorthand(), important);
+    case CSSPropertyBorder:
+        return consumeBorder(important);
     default:
         m_currentShorthand = oldShorthand;
-        return false;
+        CSSParserValueList valueList(m_range);
+        if (!valueList.size())
+            return false;
+        m_valueList = &valueList;
+        return legacyParseShorthand(unresolvedProperty, important);
     }
 }
 
diff --git a/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.h b/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.h
index d68f032..d13ae72 100644
--- a/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.h
+++ b/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.h
@@ -119,7 +119,9 @@
     bool consumeCSSWideKeyword(CSSPropertyID unresolvedProperty, bool important);
     PassRefPtrWillBeRawPtr<CSSValue> parseSingleValue(CSSPropertyID);
 
-    bool parseValue(CSSPropertyID, bool important);
+    PassRefPtrWillBeRawPtr<CSSValue> legacyParseValue(CSSPropertyID);
+    bool legacyParseAndApplyValue(CSSPropertyID, bool important);
+    bool legacyParseShorthand(CSSPropertyID, bool important);
 
     bool inShorthand() const { return m_inParseShorthand; }
     bool inQuirksMode() const { return isQuirksModeBehavior(m_context.mode()); }
@@ -130,15 +132,14 @@
     void addProperty(CSSPropertyID, PassRefPtrWillBeRawPtr<CSSValue>, bool important, bool implicit = false);
     void addExpandedPropertyForValue(CSSPropertyID propId, PassRefPtrWillBeRawPtr<CSSValue>, bool);
 
+    bool consumeBorder(bool important);
+
     PassRefPtrWillBeRawPtr<CSSPrimitiveValue> parseValidPrimitive(CSSValueID ident, CSSParserValue*);
 
-    bool parseShorthand(CSSPropertyID, const StylePropertyShorthand&, bool important);
     bool parseShorthand(CSSPropertyID, bool important);
     bool consumeShorthandGreedily(const StylePropertyShorthand&, bool important);
     bool consume4Values(const StylePropertyShorthand&, bool important);
 
-    bool parse4Values(CSSPropertyID, const CSSPropertyID* properties, bool important);
-
     bool parseFillImage(CSSParserValueList*, RefPtrWillBeRawPtr<CSSValue>&);
 
     enum FillPositionFlag { InvalidFillPosition = 0, AmbiguousFillPosition = 1, XFillPosition = 2, YFillPosition = 4 };
@@ -185,8 +186,8 @@
     bool parseGridLineNames(CSSParserValueList&, CSSValueList&, CSSGridLineNamesValue* = nullptr);
     PassRefPtrWillBeRawPtr<CSSValue> parseGridAutoFlow(CSSParserValueList&);
 
-    bool parseLegacyPosition(CSSPropertyID, bool important);
-    bool parseItemPositionOverflowPosition(CSSPropertyID, bool important);
+    PassRefPtrWillBeRawPtr<CSSValue> parseLegacyPosition();
+    PassRefPtrWillBeRawPtr<CSSValue> parseItemPositionOverflowPosition();
     PassRefPtrWillBeRawPtr<CSSValue> parseContentDistributionOverflowPosition();
 
     PassRefPtrWillBeRawPtr<CSSValue> parseShapeProperty(CSSPropertyID propId);
diff --git a/third_party/WebKit/Source/core/css/parser/LegacyCSSPropertyParser.cpp b/third_party/WebKit/Source/core/css/parser/LegacyCSSPropertyParser.cpp
index 4287922..8fc32d9 100644
--- a/third_party/WebKit/Source/core/css/parser/LegacyCSSPropertyParser.cpp
+++ b/third_party/WebKit/Source/core/css/parser/LegacyCSSPropertyParser.cpp
@@ -294,7 +294,16 @@
         addProperty(longhands[i], value, important);
 }
 
-bool CSSPropertyParser::parseValue(CSSPropertyID unresolvedProperty, bool important)
+bool CSSPropertyParser::legacyParseAndApplyValue(CSSPropertyID propertyID, bool important)
+{
+    RefPtrWillBeRawPtr<CSSValue> result = legacyParseValue(propertyID);
+    if (!result)
+        return false;
+    addProperty(propertyID, result.release(), important);
+    return true;
+}
+
+PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::legacyParseValue(CSSPropertyID unresolvedProperty)
 {
     CSSPropertyID propId = resolveCSSPropertyID(unresolvedProperty);
 
@@ -306,27 +315,12 @@
 
     CSSValueID id = value->id;
 
-    // TODO(timloh): Move to parseSingleValue
-    if (CSSParserFastPaths::isKeywordPropertyID(propId)) {
-        if (!CSSParserFastPaths::isValidKeywordPropertyAndValue(propId, id))
-            return false;
-        if (m_valueList->next() && !inShorthand())
-            return false;
-        addProperty(propId, cssValuePool().createIdentifierValue(id), important);
-        return true;
-    }
-
     bool validPrimitive = false;
-    Units unitless = FUnknown;
     RefPtrWillBeRawPtr<CSSValue> parsedValue = nullptr;
 
     switch (propId) {
     case CSSPropertyBackgroundColor: // <color> | inherit
-    case CSSPropertyBorderTopColor: // <color> | inherit
-    case CSSPropertyBorderRightColor:
-    case CSSPropertyBorderBottomColor:
-    case CSSPropertyBorderLeftColor:
-        parsedValue = parseColor(m_valueList->current(), inQuirksMode() && (!inShorthand() || m_currentShorthand == CSSPropertyBorderColor));
+        parsedValue = parseColor(m_valueList->current(), inQuirksMode() && !inShorthand());
         if (parsedValue)
             m_valueList->next();
         break;
@@ -345,45 +339,25 @@
     case CSSPropertyBackgroundOrigin:
     case CSSPropertyMaskSourceType:
     case CSSPropertyWebkitBackgroundOrigin:
-    case CSSPropertyBackgroundPosition:
     case CSSPropertyBackgroundPositionX:
     case CSSPropertyBackgroundPositionY:
     case CSSPropertyBackgroundSize:
-    case CSSPropertyBackgroundRepeat:
     case CSSPropertyWebkitMaskClip:
     case CSSPropertyWebkitMaskComposite:
     case CSSPropertyWebkitMaskImage:
     case CSSPropertyWebkitMaskOrigin:
-    case CSSPropertyWebkitMaskPosition:
     case CSSPropertyWebkitMaskPositionX:
     case CSSPropertyWebkitMaskPositionY:
     case CSSPropertyWebkitMaskSize:
-    case CSSPropertyWebkitMaskRepeat:
     case CSSPropertyWebkitMaskRepeatX:
     case CSSPropertyWebkitMaskRepeatY:
     {
-        RefPtrWillBeRawPtr<CSSValue> val1 = nullptr;
-        RefPtrWillBeRawPtr<CSSValue> val2 = nullptr;
+        RefPtrWillBeRawPtr<CSSValue> dummyValue = nullptr;
         CSSPropertyID propId1, propId2;
-        bool result = false;
-        if (parseFillProperty(unresolvedProperty, propId1, propId2, val1, val2)) {
-            if (propId == CSSPropertyBackgroundPosition ||
-                propId == CSSPropertyBackgroundRepeat ||
-                propId == CSSPropertyWebkitMaskPosition ||
-                propId == CSSPropertyWebkitMaskRepeat) {
-                ShorthandScope scope(this, propId);
-                addProperty(propId1, val1.release(), important);
-                if (val2)
-                    addProperty(propId2, val2.release(), important);
-            } else {
-                addProperty(propId1, val1.release(), important);
-                if (val2)
-                    addProperty(propId2, val2.release(), important);
-            }
-            result = true;
-        }
-        m_implicitShorthand = false;
-        return result;
+        if (!parseFillProperty(unresolvedProperty, propId1, propId2, parsedValue, dummyValue))
+            return nullptr;
+        ASSERT(!dummyValue);
+        break;
     }
     case CSSPropertyBorderImageSource: // <uri> | none | inherit
     case CSSPropertyWebkitMaskBoxImageSource:
@@ -391,18 +365,6 @@
             m_valueList->next();
         break;
 
-    case CSSPropertyBorderTopWidth:     //// <border-width> | inherit
-    case CSSPropertyBorderRightWidth:   //   Which is defined as
-    case CSSPropertyBorderBottomWidth:  //   thin | medium | thick | <length>
-    case CSSPropertyBorderLeftWidth:
-        if (!inShorthand() || m_currentShorthand == CSSPropertyBorderWidth)
-            unitless = FUnitlessQuirk;
-        if (id == CSSValueThin || id == CSSValueMedium || id == CSSValueThick)
-            validPrimitive = true;
-        else
-            validPrimitive = validUnit(value, FLength | FNonNeg | unitless);
-        break;
-
     case CSSPropertyBottom:               // <length> | <percentage> | auto | inherit
     case CSSPropertyLeft:                 // <length> | <percentage> | auto | inherit
     case CSSPropertyRight:                // <length> | <percentage> | auto | inherit
@@ -413,59 +375,37 @@
             validPrimitive = validUnit(value, FLength | FPercent | FUnitlessQuirk);
         break;
 
-    case CSSPropertySrc:
-    case CSSPropertyUnicodeRange:
-        /* @font-face only descriptors */
+    case CSSPropertyWebkitBorderImage:
+        parsedValue = parseBorderImage(propId);
         break;
 
-    /* CSS3 properties */
-
-    case CSSPropertyBorderImage:
-    case CSSPropertyWebkitMaskBoxImage:
-        return parseBorderImageShorthand(propId, important);
-    case CSSPropertyWebkitBorderImage: {
-        if (RefPtrWillBeRawPtr<CSSValue> result = parseBorderImage(propId)) {
-            addProperty(propId, result, important);
-            return true;
-        }
-        return false;
-    }
-
     case CSSPropertyBorderImageOutset:
     case CSSPropertyWebkitMaskBoxImageOutset: {
         RefPtrWillBeRawPtr<CSSQuadValue> result = nullptr;
-        if (parseBorderImageOutset(result)) {
-            addProperty(propId, result, important);
-            return true;
-        }
-        break;
+        if (parseBorderImageOutset(result))
+            return result.release();
+        return nullptr;
     }
     case CSSPropertyBorderImageRepeat:
     case CSSPropertyWebkitMaskBoxImageRepeat: {
         RefPtrWillBeRawPtr<CSSValue> result = nullptr;
-        if (parseBorderImageRepeat(result)) {
-            addProperty(propId, result, important);
-            return true;
-        }
-        break;
+        if (parseBorderImageRepeat(result))
+            return result.release();
+        return nullptr;
     }
     case CSSPropertyBorderImageSlice:
     case CSSPropertyWebkitMaskBoxImageSlice: {
         RefPtrWillBeRawPtr<CSSBorderImageSliceValue> result = nullptr;
-        if (parseBorderImageSlice(propId, result)) {
-            addProperty(propId, result, important);
-            return true;
-        }
-        break;
+        if (parseBorderImageSlice(propId, result))
+            return result.release();
+        return nullptr;
     }
     case CSSPropertyBorderImageWidth:
     case CSSPropertyWebkitMaskBoxImageWidth: {
         RefPtrWillBeRawPtr<CSSQuadValue> result = nullptr;
-        if (parseBorderImageWidth(result)) {
-            addProperty(propId, result, important);
-            return true;
-        }
-        break;
+        if (parseBorderImageWidth(result))
+            return result.release();
+        return nullptr;
     }
     case CSSPropertyWebkitBoxReflect:
         if (id == CSSValueNone)
@@ -483,15 +423,17 @@
         break;
     case CSSPropertyJustifySelf:
         ASSERT(RuntimeEnabledFeatures::cssGridLayoutEnabled());
-        return parseItemPositionOverflowPosition(propId, important);
+        parsedValue = parseItemPositionOverflowPosition();
+        break;
     case CSSPropertyJustifyItems:
         ASSERT(RuntimeEnabledFeatures::cssGridLayoutEnabled());
 
-        if (parseLegacyPosition(propId, important))
-            return true;
+        if ((parsedValue = parseLegacyPosition()))
+            break;
 
         m_valueList->setCurrentIndex(0);
-        return parseItemPositionOverflowPosition(propId, important);
+        parsedValue = parseItemPositionOverflowPosition();
+        break;
     case CSSPropertyGridAutoFlow:
         ASSERT(RuntimeEnabledFeatures::cssGridLayoutEnabled());
         parsedValue = parseGridAutoFlow(*m_valueList);
@@ -516,89 +458,19 @@
         parsedValue = parseGridPosition();
         break;
 
-    case CSSPropertyGridGap:
-        ASSERT(RuntimeEnabledFeatures::cssGridLayoutEnabled());
-        return parseGridGapShorthand(important);
-
-    case CSSPropertyGridColumn:
-    case CSSPropertyGridRow:
-        ASSERT(RuntimeEnabledFeatures::cssGridLayoutEnabled());
-        return parseGridItemPositionShorthand(propId, important);
-
-    case CSSPropertyGridArea:
-        ASSERT(RuntimeEnabledFeatures::cssGridLayoutEnabled());
-        return parseGridAreaShorthand(important);
-
     case CSSPropertyGridTemplateAreas:
         ASSERT(RuntimeEnabledFeatures::cssGridLayoutEnabled());
         parsedValue = parseGridTemplateAreas();
         break;
 
-    case CSSPropertyGridTemplate:
-        ASSERT(RuntimeEnabledFeatures::cssGridLayoutEnabled());
-        return parseGridTemplateShorthand(important);
-
-    case CSSPropertyGrid:
-        ASSERT(RuntimeEnabledFeatures::cssGridLayoutEnabled());
-        return parseGridShorthand(important);
-
-        /* shorthand properties */
-    case CSSPropertyBackground: {
-        // Position must come before color in this array because a plain old "0" is a legal color
-        // in quirks mode but it's usually the X coordinate of a position.
-        const CSSPropertyID properties[] = { CSSPropertyBackgroundImage, CSSPropertyBackgroundRepeat,
-                                   CSSPropertyBackgroundAttachment, CSSPropertyBackgroundPosition, CSSPropertyBackgroundOrigin,
-                                   CSSPropertyBackgroundClip, CSSPropertyBackgroundColor, CSSPropertyBackgroundSize };
-        return parseFillShorthand(propId, properties, WTF_ARRAY_LENGTH(properties), important);
-    }
-    case CSSPropertyWebkitMask: {
-        const CSSPropertyID properties[] = { CSSPropertyWebkitMaskImage, CSSPropertyWebkitMaskRepeat,
-            CSSPropertyWebkitMaskPosition, CSSPropertyWebkitMaskOrigin, CSSPropertyWebkitMaskClip, CSSPropertyWebkitMaskSize };
-        return parseFillShorthand(propId, properties, WTF_ARRAY_LENGTH(properties), important);
-    }
-    case CSSPropertyBorder:
-        // [ 'border-width' || 'border-style' || <color> ] | inherit
-    {
-        if (parseShorthand(propId, borderShorthandForParsing(), important)) {
-            // The CSS3 Borders and Backgrounds specification says that border also resets border-image. It's as
-            // though a value of none was specified for the image.
-            addExpandedPropertyForValue(CSSPropertyBorderImage, cssValuePool().createImplicitInitialValue(), important);
-            return true;
-        }
-        return false;
-    }
-    case CSSPropertyBorderTop:
-        // [ 'border-top-width' || 'border-style' || <color> ] | inherit
-        return parseShorthand(propId, borderTopShorthand(), important);
-    case CSSPropertyBorderRight:
-        // [ 'border-right-width' || 'border-style' || <color> ] | inherit
-        return parseShorthand(propId, borderRightShorthand(), important);
-    case CSSPropertyBorderBottom:
-        // [ 'border-bottom-width' || 'border-style' || <color> ] | inherit
-        return parseShorthand(propId, borderBottomShorthand(), important);
-    case CSSPropertyBorderLeft:
-        // [ 'border-left-width' || 'border-style' || <color> ] | inherit
-        return parseShorthand(propId, borderLeftShorthand(), important);
-    case CSSPropertyBorderColor:
-        // <color>{1,4} | inherit
-        return parse4Values(propId, borderColorShorthand().properties(), important);
-    case CSSPropertyBorderWidth:
-        // <border-width>{1,4} | inherit
-        return parse4Values(propId, borderWidthShorthand().properties(), important);
-    case CSSPropertyBorderStyle:
-        // <border-style>{1,4} | inherit
-        return parse4Values(propId, borderStyleShorthand().properties(), important);
-    case CSSPropertyInvalid:
-        return false;
     case CSSPropertyWebkitClipPath:
         if (id == CSSValueNone) {
             validPrimitive = true;
         } else if (value->m_unit == CSSParserValue::Function) {
             parsedValue = parseBasicShape();
         } else if (value->m_unit == CSSParserValue::URI) {
-            parsedValue = CSSURIValue::create(value->string);
-            addProperty(propId, parsedValue.release(), important);
-            return true;
+            // TODO(timloh): This will allow trailing junk
+            return CSSURIValue::create(value->string);
         }
         break;
     case CSSPropertyShapeOutside:
@@ -615,227 +487,17 @@
 
     case CSSPropertyAlignSelf:
         ASSERT(RuntimeEnabledFeatures::cssGridLayoutEnabled());
-        return parseItemPositionOverflowPosition(propId, important);
+        parsedValue = parseItemPositionOverflowPosition();
+        break;
 
     case CSSPropertyAlignItems:
         ASSERT(RuntimeEnabledFeatures::cssGridLayoutEnabled());
-        return parseItemPositionOverflowPosition(propId, important);
-
-    // Properties below are validated inside parseViewportProperty, because we
-    // check for parser state. We need to invalidate if someone adds them outside
-    // a @viewport rule.
-    case CSSPropertyMaxZoom:
-    case CSSPropertyMinZoom:
-    case CSSPropertyOrientation:
-    case CSSPropertyUserZoom:
-        validPrimitive = false;
+        parsedValue = parseItemPositionOverflowPosition();
         break;
 
-    // These were not accepted by the new path above so we should return false.
-    case CSSPropertyWebkitPerspectiveOriginX:
-    case CSSPropertyWebkitTransformOriginX:
-    case CSSPropertyWebkitPerspectiveOriginY:
-    case CSSPropertyWebkitTransformOriginY:
-    case CSSPropertyWebkitTransformOriginZ:
-    case CSSPropertyWebkitMarginCollapse:
-    case CSSPropertyWillChange:
-    case CSSPropertyPage:
-    case CSSPropertyOverflow:
-    case CSSPropertyQuotes:
-    case CSSPropertyWebkitHighlight:
-    case CSSPropertyFontVariantLigatures:
-    case CSSPropertyFontFeatureSettings:
-    case CSSPropertyFontVariant:
-    case CSSPropertyFontFamily:
-    case CSSPropertyFontWeight:
-    case CSSPropertyLetterSpacing:
-    case CSSPropertyWordSpacing:
-    case CSSPropertyTabSize:
-    case CSSPropertyFontSize:
-    case CSSPropertyLineHeight:
-    case CSSPropertyRotate:
-    case CSSPropertyFont:
-    case CSSPropertyWebkitBorderHorizontalSpacing:
-    case CSSPropertyWebkitBorderVerticalSpacing:
-    case CSSPropertyBorderSpacing:
-    case CSSPropertyCounterIncrement:
-    case CSSPropertyCounterReset:
-    case CSSPropertySize:
-    case CSSPropertyTextIndent:
-    case CSSPropertyMaxWidth:
-    case CSSPropertyMaxHeight:
-    case CSSPropertyWebkitMaxLogicalWidth:
-    case CSSPropertyWebkitMaxLogicalHeight:
-    case CSSPropertyMinWidth:
-    case CSSPropertyMinHeight:
-    case CSSPropertyWidth:
-    case CSSPropertyHeight:
-    case CSSPropertyWebkitMinLogicalWidth:
-    case CSSPropertyWebkitMinLogicalHeight:
-    case CSSPropertyWebkitLogicalWidth:
-    case CSSPropertyWebkitLogicalHeight:
-    case CSSPropertyScrollSnapDestination:
-    case CSSPropertyObjectPosition:
-    case CSSPropertyPerspectiveOrigin:
-    case CSSPropertyClip:
-    case CSSPropertyTouchAction:
-    case CSSPropertyWebkitLineClamp:
-    case CSSPropertyWebkitFontSizeDelta:
-    case CSSPropertyWebkitHyphenateCharacter:
-    case CSSPropertyWebkitLocale:
-    case CSSPropertyWebkitColumnWidth:
-    case CSSPropertyWebkitColumnCount:
-    case CSSPropertyWebkitColumns:
-    case CSSPropertyWebkitColumnGap:
-    case CSSPropertyWebkitColumnSpan:
-    case CSSPropertyZoom:
-    case CSSPropertyAnimation:
-    case CSSPropertyTransition:
-    case CSSPropertyAnimationDelay:
-    case CSSPropertyTransitionDelay:
-    case CSSPropertyAnimationDirection:
-    case CSSPropertyAnimationDuration:
-    case CSSPropertyTransitionDuration:
-    case CSSPropertyAnimationFillMode:
-    case CSSPropertyAnimationIterationCount:
-    case CSSPropertyAnimationName:
-    case CSSPropertyAnimationPlayState:
-    case CSSPropertyAnimationTimingFunction:
-    case CSSPropertyTransitionTimingFunction:
-    case CSSPropertyTransitionProperty:
-    case CSSPropertyGridColumnGap:
-    case CSSPropertyGridRowGap:
-    case CSSPropertyShapeMargin:
-    case CSSPropertyShapeImageThreshold:
-    case CSSPropertyWebkitBoxOrdinalGroup:
-    case CSSPropertyOrphans:
-    case CSSPropertyWidows:
-    case CSSPropertyWebkitTapHighlightColor:
-    case CSSPropertyWebkitTextFillColor:
-    case CSSPropertyColor:
-    case CSSPropertyZIndex:
-    case CSSPropertyTextShadow:
-    case CSSPropertyBoxShadow:
-    case CSSPropertyWebkitFilter:
-    case CSSPropertyBackdropFilter:
-    case CSSPropertyTextDecorationColor:
-    case CSSPropertyWebkitTextDecorationsInEffect:
-    case CSSPropertyTextDecorationLine:
-    case CSSPropertyTextDecoration:
-    case CSSPropertyMotionPath:
-    case CSSPropertyMotionOffset:
-    case CSSPropertyMotionRotation:
-    case CSSPropertyMotion:
-    case CSSPropertyWebkitTextEmphasisColor:
-    case CSSPropertyWebkitTextEmphasisStyle:
-    case CSSPropertyWebkitTextEmphasis:
-    case CSSPropertyOutline:
-    case CSSPropertyOutlineColor:
-    case CSSPropertyOutlineWidth:
-    case CSSPropertyOutlineOffset:
-    case CSSPropertyWebkitBorderStartColor:
-    case CSSPropertyWebkitBorderEndColor:
-    case CSSPropertyWebkitBorderBeforeColor:
-    case CSSPropertyWebkitBorderAfterColor:
-    case CSSPropertyWebkitBorderStartWidth:
-    case CSSPropertyWebkitBorderEndWidth:
-    case CSSPropertyWebkitBorderBeforeWidth:
-    case CSSPropertyWebkitBorderAfterWidth:
-    case CSSPropertyWebkitBorderStart:
-    case CSSPropertyWebkitBorderEnd:
-    case CSSPropertyWebkitBorderBefore:
-    case CSSPropertyWebkitBorderAfter:
-    case CSSPropertyWebkitTextStroke:
-    case CSSPropertyWebkitTextStrokeColor:
-    case CSSPropertyWebkitTextStrokeWidth:
-    case CSSPropertyTransform:
-    case CSSPropertyFill:
-    case CSSPropertyStroke:
-    case CSSPropertyStopColor:
-    case CSSPropertyFloodColor:
-    case CSSPropertyLightingColor:
-    case CSSPropertyPaintOrder:
-    case CSSPropertyMarginTop:
-    case CSSPropertyMarginRight:
-    case CSSPropertyMarginBottom:
-    case CSSPropertyMarginLeft:
-    case CSSPropertyMargin:
-    case CSSPropertyWebkitMarginStart:
-    case CSSPropertyWebkitMarginEnd:
-    case CSSPropertyWebkitMarginBefore:
-    case CSSPropertyWebkitMarginAfter:
-    case CSSPropertyPaddingTop:
-    case CSSPropertyPaddingRight:
-    case CSSPropertyPaddingBottom:
-    case CSSPropertyPaddingLeft:
-    case CSSPropertyPadding:
-    case CSSPropertyWebkitPaddingStart:
-    case CSSPropertyWebkitPaddingEnd:
-    case CSSPropertyWebkitPaddingBefore:
-    case CSSPropertyWebkitPaddingAfter:
-    case CSSPropertyMarker:
-    case CSSPropertyMarkerStart:
-    case CSSPropertyMarkerMid:
-    case CSSPropertyMarkerEnd:
-    case CSSPropertyFlex:
-    case CSSPropertyFlexBasis:
-    case CSSPropertyFlexGrow:
-    case CSSPropertyFlexShrink:
-    case CSSPropertyFlexFlow:
-    case CSSPropertyStrokeDasharray:
-    case CSSPropertyD:
-    case CSSPropertyWebkitColumnRule:
-    case CSSPropertyWebkitColumnRuleColor:
-    case CSSPropertyWebkitColumnRuleWidth:
-    case CSSPropertyClipPath:
-    case CSSPropertyFilter:
-    case CSSPropertyMask:
-    case CSSPropertyStrokeOpacity:
-    case CSSPropertyFillOpacity:
-    case CSSPropertyStopOpacity:
-    case CSSPropertyFloodOpacity:
-    case CSSPropertyOpacity:
-    case CSSPropertyWebkitBoxFlex:
-    case CSSPropertyBaselineShift:
-    case CSSPropertyStrokeMiterlimit:
-    case CSSPropertyStrokeWidth:
-    case CSSPropertyStrokeDashoffset:
-    case CSSPropertyCx:
-    case CSSPropertyCy:
-    case CSSPropertyX:
-    case CSSPropertyY:
-    case CSSPropertyR:
-    case CSSPropertyRx:
-    case CSSPropertyRy:
-    case CSSPropertyScale:
-    case CSSPropertyTranslate:
-    case CSSPropertyCursor:
-    case CSSPropertyTransformOrigin:
-    case CSSPropertyContent:
-    case CSSPropertyListStyleImage:
-    case CSSPropertyListStyle:
-    case CSSPropertyPerspective:
-    case CSSPropertyScrollSnapCoordinate:
-    case CSSPropertyScrollSnapPointsX:
-    case CSSPropertyScrollSnapPointsY:
-    case CSSPropertyBorderTopRightRadius:
-    case CSSPropertyBorderTopLeftRadius:
-    case CSSPropertyBorderBottomLeftRadius:
-    case CSSPropertyBorderBottomRightRadius:
-    case CSSPropertyBorderRadius:
-    case CSSPropertyAliasWebkitBorderRadius:
-    case CSSPropertyWebkitBoxFlexGroup:
-    case CSSPropertyOrder:
-    case CSSPropertyTextUnderlinePosition:
-    case CSSPropertyVerticalAlign:
-        validPrimitive = false;
-        break;
-
+    // Everything else is handled in CSSPropertyParser.cpp
     default:
-        // If you crash here, it's because you added a css property and are not handling it
-        // in either this switch statement or the one in CSSPropertyParser::parseSingleValue.
-        ASSERT_WITH_MESSAGE(0, "unimplemented propertyID: %d", propId);
-        return false;
+        return nullptr;
     }
 
     if (validPrimitive) {
@@ -844,12 +506,77 @@
     }
     ASSERT(!m_parsedCalculation);
     if (parsedValue) {
-        if (!m_valueList->current() || inShorthand()) {
-            addProperty(propId, parsedValue.release(), important);
+        if (!m_valueList->current() || inShorthand())
+            return parsedValue.release();
+    }
+    return nullptr;
+}
+
+bool CSSPropertyParser::legacyParseShorthand(CSSPropertyID propertyID, bool important)
+{
+    switch (propertyID) {
+    case CSSPropertyBackgroundPosition:
+    case CSSPropertyBackgroundRepeat:
+    case CSSPropertyWebkitMaskPosition:
+    case CSSPropertyWebkitMaskRepeat: {
+        RefPtrWillBeRawPtr<CSSValue> val1 = nullptr;
+        RefPtrWillBeRawPtr<CSSValue> val2 = nullptr;
+        CSSPropertyID propId1, propId2;
+        if (parseFillProperty(propertyID, propId1, propId2, val1, val2)) {
+            ShorthandScope scope(this, propertyID);
+            addProperty(propId1, val1.release(), important);
+            if (val2)
+                addProperty(propId2, val2.release(), important);
+            m_implicitShorthand = false;
             return true;
         }
+        m_implicitShorthand = false;
+        return true;
     }
-    return false;
+
+    case CSSPropertyBorderImage:
+    case CSSPropertyWebkitMaskBoxImage:
+        return parseBorderImageShorthand(propertyID, important);
+
+    case CSSPropertyGridGap:
+        ASSERT(RuntimeEnabledFeatures::cssGridLayoutEnabled());
+        return parseGridGapShorthand(important);
+
+    case CSSPropertyGridColumn:
+    case CSSPropertyGridRow:
+        ASSERT(RuntimeEnabledFeatures::cssGridLayoutEnabled());
+        return parseGridItemPositionShorthand(propertyID, important);
+
+    case CSSPropertyGridArea:
+        ASSERT(RuntimeEnabledFeatures::cssGridLayoutEnabled());
+        return parseGridAreaShorthand(important);
+
+    case CSSPropertyGridTemplate:
+        ASSERT(RuntimeEnabledFeatures::cssGridLayoutEnabled());
+        return parseGridTemplateShorthand(important);
+
+    case CSSPropertyGrid:
+        ASSERT(RuntimeEnabledFeatures::cssGridLayoutEnabled());
+        return parseGridShorthand(important);
+
+    case CSSPropertyBackground: {
+        // Position must come before color in this array because a plain old "0" is a legal color
+        // in quirks mode but it's usually the X coordinate of a position.
+        const CSSPropertyID properties[] = { CSSPropertyBackgroundImage, CSSPropertyBackgroundRepeat,
+                                   CSSPropertyBackgroundAttachment, CSSPropertyBackgroundPosition, CSSPropertyBackgroundOrigin,
+                                   CSSPropertyBackgroundClip, CSSPropertyBackgroundColor, CSSPropertyBackgroundSize };
+        return parseFillShorthand(propertyID, properties, WTF_ARRAY_LENGTH(properties), important);
+    }
+    case CSSPropertyWebkitMask: {
+        const CSSPropertyID properties[] = { CSSPropertyWebkitMaskImage, CSSPropertyWebkitMaskRepeat,
+            CSSPropertyWebkitMaskPosition, CSSPropertyWebkitMaskOrigin, CSSPropertyWebkitMaskClip, CSSPropertyWebkitMaskSize };
+        return parseFillShorthand(propertyID, properties, WTF_ARRAY_LENGTH(properties), important);
+    }
+
+    // The remaining shorthands are handled in CSSPropertyParser.cpp
+    default:
+        return false;
+    }
 }
 
 void CSSPropertyParser::addFillValue(RefPtrWillBeRawPtr<CSSValue>& lval, PassRefPtrWillBeRawPtr<CSSValue> rval)
@@ -1034,111 +761,6 @@
     return true;
 }
 
-bool CSSPropertyParser::parseShorthand(CSSPropertyID propId, const StylePropertyShorthand& shorthand, bool important)
-{
-    // We try to match as many properties as possible
-    // We set up an array of booleans to mark which property has been found,
-    // and we try to search for properties until it makes no longer any sense.
-    ShorthandScope scope(this, propId);
-
-    bool found = false;
-    unsigned propertiesParsed = 0;
-    bool propertyFound[6] = { false, false, false, false, false, false }; // 6 is enough size.
-
-    while (m_valueList->current()) {
-        found = false;
-        for (unsigned propIndex = 0; !found && propIndex < shorthand.length(); ++propIndex) {
-            if (!propertyFound[propIndex] && parseValue(shorthand.properties()[propIndex], important)) {
-                propertyFound[propIndex] = found = true;
-                propertiesParsed++;
-            }
-        }
-
-        // if we didn't find at least one match, this is an
-        // invalid shorthand and we have to ignore it
-        if (!found)
-            return false;
-    }
-
-    if (propertiesParsed == shorthand.length())
-        return true;
-
-    // Fill in any remaining properties with the initial value.
-    ImplicitScope implicitScope(this);
-    const StylePropertyShorthand* const* const propertiesForInitialization = shorthand.propertiesForInitialization();
-    for (unsigned i = 0; i < shorthand.length(); ++i) {
-        if (propertyFound[i])
-            continue;
-
-        if (propertiesForInitialization) {
-            const StylePropertyShorthand& initProperties = *(propertiesForInitialization[i]);
-            for (unsigned propIndex = 0; propIndex < initProperties.length(); ++propIndex)
-                addProperty(initProperties.properties()[propIndex], cssValuePool().createImplicitInitialValue(), important);
-        } else
-            addProperty(shorthand.properties()[i], cssValuePool().createImplicitInitialValue(), important);
-    }
-
-    return true;
-}
-
-bool CSSPropertyParser::parse4Values(CSSPropertyID propId, const CSSPropertyID *properties,  bool important)
-{
-    /* From the CSS 2 specs, 8.3
-     * If there is only one value, it applies to all sides. If there are two values, the top and
-     * bottom margins are set to the first value and the right and left margins are set to the second.
-     * If there are three values, the top is set to the first value, the left and right are set to the
-     * second, and the bottom is set to the third. If there are four values, they apply to the top,
-     * right, bottom, and left, respectively.
-     */
-
-    int num = inShorthand() ? 1 : m_valueList->size();
-
-    ShorthandScope scope(this, propId);
-
-    // the order is top, right, bottom, left
-    switch (num) {
-        case 1: {
-            if (!parseValue(properties[0], important))
-                return false;
-            CSSValue* value = m_parsedProperties.last().value();
-            ImplicitScope implicitScope(this);
-            addProperty(properties[1], value, important);
-            addProperty(properties[2], value, important);
-            addProperty(properties[3], value, important);
-            break;
-        }
-        case 2: {
-            if (!parseValue(properties[0], important) || !parseValue(properties[1], important))
-                return false;
-            CSSValue* value = m_parsedProperties[m_parsedProperties.size() - 2].value();
-            ImplicitScope implicitScope(this);
-            addProperty(properties[2], value, important);
-            value = m_parsedProperties[m_parsedProperties.size() - 2].value();
-            addProperty(properties[3], value, important);
-            break;
-        }
-        case 3: {
-            if (!parseValue(properties[0], important) || !parseValue(properties[1], important) || !parseValue(properties[2], important))
-                return false;
-            CSSValue* value = m_parsedProperties[m_parsedProperties.size() - 2].value();
-            ImplicitScope implicitScope(this);
-            addProperty(properties[3], value, important);
-            break;
-        }
-        case 4: {
-            if (!parseValue(properties[0], important) || !parseValue(properties[1], important) ||
-                !parseValue(properties[2], important) || !parseValue(properties[3], important))
-                return false;
-            break;
-        }
-        default: {
-            return false;
-        }
-    }
-
-    return true;
-}
-
 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseColor(const CSSParserValue* value, bool acceptQuirkyColors)
 {
     CSSValueID id = value->id;
@@ -2096,7 +1718,7 @@
     m_valueList->setCurrentIndex(0);
 
     // 2- <grid-auto-flow> [ <grid-auto-columns> [ / <grid-auto-rows> ]? ]
-    if (!parseValue(CSSPropertyGridAutoFlow, important))
+    if (!legacyParseAndApplyValue(CSSPropertyGridAutoFlow, important))
         return false;
 
     RefPtrWillBeRawPtr<CSSValue> autoColumnsValue = nullptr;
@@ -2645,7 +2267,7 @@
         || id == CSSValueFlexEnd || id == CSSValueLeft || id == CSSValueRight;
 }
 
-bool CSSPropertyParser::parseLegacyPosition(CSSPropertyID propId, bool important)
+PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseLegacyPosition()
 {
     // [ legacy && [ left | right | center ]
 
@@ -2655,18 +2277,18 @@
     if (value->id == CSSValueLegacy) {
         value = m_valueList->next();
         if (!value)
-            return false;
+            return nullptr;
         if (value->id != CSSValueCenter && value->id != CSSValueLeft && value->id != CSSValueRight)
-            return false;
+            return nullptr;
     } else if (value->id == CSSValueCenter || value->id == CSSValueLeft || value->id == CSSValueRight) {
         if (!m_valueList->next() || m_valueList->current()->id != CSSValueLegacy)
-            return false;
+            return nullptr;
     } else {
-        return false;
+        return nullptr;
     }
 
-    addProperty(propId, CSSValuePair::create(cssValuePool().createIdentifierValue(CSSValueLegacy), cssValuePool().createIdentifierValue(value->id), CSSValuePair::DropIdenticalValues), important);
-    return !m_valueList->next();
+    m_valueList->next();
+    return CSSValuePair::create(cssValuePool().createIdentifierValue(CSSValueLegacy), cssValuePool().createIdentifierValue(value->id), CSSValuePair::DropIdenticalValues);
 }
 
 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseContentDistributionOverflowPosition()
@@ -2718,7 +2340,7 @@
     return CSSContentDistributionValue::create(distribution, position, overflow);
 }
 
-bool CSSPropertyParser::parseItemPositionOverflowPosition(CSSPropertyID propId, bool important)
+PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseItemPositionOverflowPosition()
 {
     // auto | stretch | <baseline-position> | [<item-position> && <overflow-position>? ]
     // <baseline-position> = baseline | last-baseline;
@@ -2729,11 +2351,8 @@
     ASSERT(value);
 
     if (value->id == CSSValueAuto || value->id == CSSValueStretch || isBaselinePositionKeyword(value->id)) {
-        if (m_valueList->next())
-            return false;
-
-        addProperty(propId, cssValuePool().createIdentifierValue(value->id), important);
-        return true;
+        m_valueList->next();
+        return cssValuePool().createIdentifierValue(value->id);
     }
 
     RefPtrWillBeRawPtr<CSSPrimitiveValue> position = nullptr;
@@ -2745,7 +2364,7 @@
             if (isAlignmentOverflowKeyword(value->id))
                 overflowAlignmentKeyword = cssValuePool().createIdentifierValue(value->id);
             else
-                return false;
+                return nullptr;
         }
     } else if (isAlignmentOverflowKeyword(value->id)) {
         overflowAlignmentKeyword = cssValuePool().createIdentifierValue(value->id);
@@ -2753,21 +2372,17 @@
         if (value && isItemPositionKeyword(value->id))
             position = cssValuePool().createIdentifierValue(value->id);
         else
-            return false;
+            return nullptr;
     } else {
-        return false;
+        return nullptr;
     }
 
-    if (m_valueList->next())
-        return false;
+    m_valueList->next();
 
     ASSERT(position);
     if (overflowAlignmentKeyword)
-        addProperty(propId, CSSValuePair::create(position, overflowAlignmentKeyword, CSSValuePair::DropIdenticalValues), important);
-    else
-        addProperty(propId, position.release(), important);
-
-    return true;
+        return CSSValuePair::create(position, overflowAlignmentKeyword, CSSValuePair::DropIdenticalValues);
+    return position.release();
 }
 
 PassRefPtrWillBeRawPtr<CSSPrimitiveValue> CSSPropertyParser::parseShapeRadius(CSSParserValue* value)
diff --git a/third_party/WebKit/Source/core/dom/Element.cpp b/third_party/WebKit/Source/core/dom/Element.cpp
index 821c32e..c9099642 100644
--- a/third_party/WebKit/Source/core/dom/Element.cpp
+++ b/third_party/WebKit/Source/core/dom/Element.cpp
@@ -571,7 +571,7 @@
     // Handle the scrollingElement separately, as it scrolls the viewport.
     if (this == document().scrollingElement()) {
         FloatSize delta(deltaX, deltaY);
-        if (document().frame()->applyScrollDelta(delta, scrollState.isBeginning()).didScroll()) {
+        if (document().frame()->applyScrollDelta(ScrollByPrecisePixel, delta, scrollState.isBeginning()).didScroll()) {
             scrolled = true;
             scrollState.consumeDeltaNative(scrollState.deltaX(), scrollState.deltaY());
         }
diff --git a/third_party/WebKit/Source/core/dom/IntersectionObservation.cpp b/third_party/WebKit/Source/core/dom/IntersectionObservation.cpp
index 1f06da2f..a32edd7 100644
--- a/third_party/WebKit/Source/core/dom/IntersectionObservation.cpp
+++ b/third_party/WebKit/Source/core/dom/IntersectionObservation.cpp
@@ -161,9 +161,15 @@
 
 void IntersectionObservation::disconnect()
 {
+    IntersectionObserver* observer = m_observer;
+    clearRootAndRemoveFromTarget();
+    observer->removeObservation(*this);
+}
+
+void IntersectionObservation::clearRootAndRemoveFromTarget()
+{
     if (m_target)
-        target()->ensureIntersectionObserverData().removeObservation(this->observer());
-    m_observer->removeObservation(*this);
+        target()->ensureIntersectionObserverData().removeObservation(observer());
     m_observer.clear();
 }
 
diff --git a/third_party/WebKit/Source/core/dom/IntersectionObservation.h b/third_party/WebKit/Source/core/dom/IntersectionObservation.h
index 7299922f..9388af9 100644
--- a/third_party/WebKit/Source/core/dom/IntersectionObservation.h
+++ b/third_party/WebKit/Source/core/dom/IntersectionObservation.h
@@ -32,9 +32,9 @@
     unsigned lastThresholdIndex() const { return m_lastThresholdIndex; }
     void setLastThresholdIndex(unsigned index) { m_lastThresholdIndex = index; }
     bool shouldReportRootBounds() const { return m_shouldReportRootBounds; }
-
     void computeIntersectionObservations(double timestamp);
     void disconnect();
+    void clearRootAndRemoveFromTarget();
 
     DECLARE_TRACE();
 
diff --git a/third_party/WebKit/Source/core/dom/IntersectionObserver.cpp b/third_party/WebKit/Source/core/dom/IntersectionObserver.cpp
index b29b69e8..efe97c9 100644
--- a/third_party/WebKit/Source/core/dom/IntersectionObserver.cpp
+++ b/third_party/WebKit/Source/core/dom/IntersectionObserver.cpp
@@ -152,6 +152,16 @@
     root.document().ensureIntersectionObserverController().addTrackedObserver(*this);
 }
 
+#if ENABLE(OILPAN)
+void IntersectionObserver::clearWeakMembers(Visitor* visitor)
+{
+    if (Heap::isHeapObjectAlive(m_root))
+        return;
+    disconnect();
+    m_root = nullptr;
+}
+#endif
+
 LayoutObject* IntersectionObserver::rootLayoutObject() const
 {
     Node* rootNode = root();
@@ -186,7 +196,6 @@
 
 void IntersectionObserver::observe(Element* target, ExceptionState& exceptionState)
 {
-    checkRootAndDetachIfNeeded();
     if (!m_root) {
         exceptionState.throwDOMException(HierarchyRequestError, "Invalid observer: root element or containing document has been deleted.");
         return;
@@ -221,7 +230,6 @@
 
 void IntersectionObserver::unobserve(Element* target, ExceptionState&)
 {
-    checkRootAndDetachIfNeeded();
     if (!target || !target->intersectionObserverData())
         return;
     // TODO(szager): unobserve callback
@@ -231,7 +239,6 @@
 
 void IntersectionObserver::computeIntersectionObservations(double timestamp)
 {
-    checkRootAndDetachIfNeeded();
     if (!m_root)
         return;
     for (auto& observation : m_observations)
@@ -240,11 +247,9 @@
 
 void IntersectionObserver::disconnect()
 {
-    HeapVector<Member<IntersectionObservation>> observationsToDisconnect;
-    copyToVector(m_observations, observationsToDisconnect);
-    for (auto& observation : observationsToDisconnect)
-        observation->disconnect();
-    ASSERT(m_observations.isEmpty());
+    for (auto& observation : m_observations)
+        observation->clearRootAndRemoveFromTarget();
+    m_observations.clear();
 }
 
 void IntersectionObserver::removeObservation(IntersectionObservation& observation)
@@ -254,7 +259,6 @@
 
 HeapVector<Member<IntersectionObserverEntry>> IntersectionObserver::takeRecords()
 {
-    checkRootAndDetachIfNeeded();
     HeapVector<Member<IntersectionObserverEntry>> entries;
     entries.swap(m_entries);
     return entries;
@@ -299,7 +303,6 @@
 
 void IntersectionObserver::deliver()
 {
-    checkRootAndDetachIfNeeded();
 
     if (m_entries.isEmpty())
         return;
@@ -311,7 +314,6 @@
 
 void IntersectionObserver::setActive(bool active)
 {
-    checkRootAndDetachIfNeeded();
     for (auto& observation : m_observations)
         observation->setActive(m_root && active && isDescendantOfRoot(observation->target()));
 }
@@ -324,27 +326,12 @@
         || m_leftMargin.type() == Percent);
 }
 
-void IntersectionObserver::checkRootAndDetachIfNeeded()
-{
-#if ENABLE(OILPAN)
-    // TODO(szager): Pre-oilpan, ElementIntersectionObserverData::dispose() will take
-    // care of this cleanup.  When oilpan ships, there will be a potential leak of the
-    // callback's execution context when the root goes away.  For a detailed explanation:
-    //
-    //   https://goo.gl/PC2Baj
-    //
-    // When that happens, this method should catch most potential leaks, but a complete
-    // solution will still be needed, along the lines described in the above link.
-    if (m_root)
-        return;
-    disconnect();
-#endif
-}
-
 DEFINE_TRACE(IntersectionObserver)
 {
+#if ENABLE(OILPAN)
+    visitor->template registerWeakMembers<IntersectionObserver, &IntersectionObserver::clearWeakMembers>(this);
+#endif
     visitor->trace(m_callback);
-    visitor->trace(m_root);
     visitor->trace(m_observations);
     visitor->trace(m_entries);
 }
diff --git a/third_party/WebKit/Source/core/dom/IntersectionObserver.h b/third_party/WebKit/Source/core/dom/IntersectionObserver.h
index f793a6f..d3e61cd9 100644
--- a/third_party/WebKit/Source/core/dom/IntersectionObserver.h
+++ b/third_party/WebKit/Source/core/dom/IntersectionObserver.h
@@ -55,8 +55,9 @@
 
 private:
     explicit IntersectionObserver(IntersectionObserverCallback&, Node&, const Vector<Length>& rootMargin, const Vector<float>& thresholds);
-
-    void checkRootAndDetachIfNeeded();
+#if ENABLE(OILPAN)
+    void clearWeakMembers(Visitor*);
+#endif
 
     Member<IntersectionObserverCallback> m_callback;
     WeakPtrWillBeWeakMember<Node> m_root;
diff --git a/third_party/WebKit/Source/core/editing/VisibleUnits.cpp b/third_party/WebKit/Source/core/editing/VisibleUnits.cpp
index dea64c5..22b0234 100644
--- a/third_party/WebKit/Source/core/editing/VisibleUnits.cpp
+++ b/third_party/WebKit/Source/core/editing/VisibleUnits.cpp
@@ -673,7 +673,7 @@
         TextIteratorAlgorithm<Strategy> forwardsIterator(end, PositionTemplate<Strategy>::afterNode(boundary));
         while (!forwardsIterator.atEnd()) {
             Vector<UChar, 1024> characters;
-            forwardsIterator.appendTextTo(characters);
+            forwardsIterator.copyTextTo(characters);
             int i = endOfFirstWordBoundaryContext(characters.data(), characters.size());
             string.append(characters.data(), i);
             suffixLength += i;
@@ -693,7 +693,7 @@
         // TODO(xiaochengh): Iterative prepending has quadratic running time
         // in the worst case. Should improve it to linear.
         if (!inTextSecurityMode) {
-            it.prependTextTo(string);
+            it.copyTextTo(string);
         } else {
             // Treat bullets used in the text security mode as regular
             // characters when looking for boundaries
@@ -753,7 +753,7 @@
         SimplifiedBackwardsTextIteratorAlgorithm<Strategy> backwardsIterator(PositionTemplate<Strategy>::firstPositionInNode(&d), start);
         while (!backwardsIterator.atEnd()) {
             Vector<UChar, 1024> characters;
-            backwardsIterator.prependTextTo(characters);
+            backwardsIterator.copyTextTo(characters);
             int length = characters.size();
             int i = startOfLastWordBoundaryContext(characters.data(), length);
             // TODO(xiaochengh): Iterative prepending has quadratic running
@@ -779,7 +779,7 @@
         // it.
         bool inTextSecurityMode = it.isInTextSecurityMode();
         if (!inTextSecurityMode) {
-            it.appendTextTo(string);
+            it.copyTextTo(string);
         } else {
             // Treat bullets used in the text security mode as regular
             // characters when looking for boundaries
diff --git a/third_party/WebKit/Source/core/editing/iterators/CharacterIterator.h b/third_party/WebKit/Source/core/editing/iterators/CharacterIterator.h
index 82a46bb..8540c72 100644
--- a/third_party/WebKit/Source/core/editing/iterators/CharacterIterator.h
+++ b/third_party/WebKit/Source/core/editing/iterators/CharacterIterator.h
@@ -53,7 +53,7 @@
     UChar characterAt(unsigned index) const { return m_textIterator.text().characterAt(m_runOffset + index); }
 
     template<typename BufferType>
-    void appendTextTo(BufferType& output) { m_textIterator.appendTextTo(output, m_runOffset); }
+    void appendTextTo(BufferType& output) { m_textIterator.copyTextTo(output, m_runOffset); }
 
     int characterOffset() const { return m_offset; }
     EphemeralRangeTemplate<Strategy> range() const;
diff --git a/third_party/WebKit/Source/core/editing/iterators/SearchBuffer.cpp b/third_party/WebKit/Source/core/editing/iterators/SearchBuffer.cpp
index f829b23..9d60f34 100644
--- a/third_party/WebKit/Source/core/editing/iterators/SearchBuffer.cpp
+++ b/third_party/WebKit/Source/core/editing/iterators/SearchBuffer.cpp
@@ -381,7 +381,7 @@
     if (buffer.needsMoreContext()) {
         for (SimplifiedBackwardsTextIteratorAlgorithm<Strategy> backwardsIterator(PositionTemplate<Strategy>::firstPositionInNode(it.ownerDocument()), PositionTemplate<Strategy>(it.currentContainer(), it.startOffset())); !backwardsIterator.atEnd(); backwardsIterator.advance()) {
             Vector<UChar, 1024> characters;
-            backwardsIterator.prependTextTo(characters);
+            backwardsIterator.copyTextTo(characters);
             buffer.prependContext(characters.data(), characters.size());
             if (!buffer.needsMoreContext())
                 break;
diff --git a/third_party/WebKit/Source/core/editing/iterators/SimplifiedBackwardsTextIterator.h b/third_party/WebKit/Source/core/editing/iterators/SimplifiedBackwardsTextIterator.h
index 4e83851..58ad56a 100644
--- a/third_party/WebKit/Source/core/editing/iterators/SimplifiedBackwardsTextIterator.h
+++ b/third_party/WebKit/Source/core/editing/iterators/SimplifiedBackwardsTextIterator.h
@@ -57,13 +57,10 @@
 
     Node* node() const { return m_node; }
 
-    template<typename BufferType>
-    void prependTextTo(BufferType& output) { prependTextTo(output, 0, m_textLength); }
-
     // Prepend characters with offset range [position, position + copyLength)
     // to the output buffer.
     template<typename BufferType>
-    void prependTextTo(BufferType& output, int position, int copyLength)
+    void copyTextTo(BufferType& output, int position, int copyLength) const
     {
         ASSERT(position >= 0);
         ASSERT(copyLength >= 0);
@@ -80,6 +77,9 @@
             m_textContainer.prependTo(output, m_textOffset + m_textLength - position - copyLength, copyLength);
     }
 
+    template<typename BufferType>
+    void copyTextTo(BufferType& output, int position = 0) const { copyTextTo(output, position, m_textLength - position); }
+
     Node* startContainer() const;
     int endOffset() const;
     PositionTemplate<Strategy> startPosition() const;
diff --git a/third_party/WebKit/Source/core/editing/iterators/SimplifiedBackwardsTextIteratorTest.cpp b/third_party/WebKit/Source/core/editing/iterators/SimplifiedBackwardsTextIteratorTest.cpp
index 39fedb9..89ad1c4 100644
--- a/third_party/WebKit/Source/core/editing/iterators/SimplifiedBackwardsTextIteratorTest.cpp
+++ b/third_party/WebKit/Source/core/editing/iterators/SimplifiedBackwardsTextIteratorTest.cpp
@@ -20,7 +20,7 @@
     const EphemeralRangeTemplate<Strategy> range = EphemeralRangeTemplate<Strategy>::rangeOfContents(element);
     Vector<UChar> buffer;
     for (SimplifiedBackwardsTextIteratorAlgorithm<Strategy> it(range.startPosition(), range.endPosition()); !it.atEnd(); it.advance()) {
-        it.prependTextTo(buffer);
+        it.copyTextTo(buffer);
     }
     return String(buffer);
 }
@@ -90,7 +90,7 @@
     EXPECT_EQ('t', backIter2.characterAt(5)) << message2;
 }
 
-TEST_F(SimplifiedBackwardsTextIteratorTest, prependTextTo)
+TEST_F(SimplifiedBackwardsTextIteratorTest, copyTextTo)
 {
     const char* bodyContent = "<a id=host><b id=one>one</b> not appeared <b id=two>two</b></a>";
     const char* shadowContent = "three <content select=#two></content> <content select=#one></content> zero";
@@ -104,40 +104,40 @@
     EphemeralRangeTemplate<EditingStrategy> range1(EphemeralRangeTemplate<EditingStrategy>::rangeOfContents(*host));
     SimplifiedBackwardsTextIteratorAlgorithm<EditingStrategy> backIter1(range1.startPosition(), range1.endPosition());
     Vector<UChar> output1;
-    backIter1.prependTextTo(output1, 0, 2);
+    backIter1.copyTextTo(output1, 0, 2);
     EXPECT_EQ("wo", String(output1)) << String::format(message, 1, "wo").utf8().data();
-    backIter1.prependTextTo(output1, 2, 1);
+    backIter1.copyTextTo(output1, 2, 1);
     EXPECT_EQ("two", String(output1)) << String::format(message, 1, "two").utf8().data();
     backIter1.advance();
-    backIter1.prependTextTo(output1, 0, 1);
+    backIter1.copyTextTo(output1, 0, 1);
     EXPECT_EQ("etwo", String(output1)) << String::format(message, 1, "etwo").utf8().data();
-    backIter1.prependTextTo(output1, 1, 2);
+    backIter1.copyTextTo(output1, 1, 2);
     EXPECT_EQ("onetwo", String(output1)) << String::format(message, 1, "onetwo").utf8().data();
 
     EphemeralRangeTemplate<EditingInComposedTreeStrategy> range2(EphemeralRangeTemplate<EditingInComposedTreeStrategy>::rangeOfContents(*host));
     SimplifiedBackwardsTextIteratorAlgorithm<EditingInComposedTreeStrategy> backIter2(range2.startPosition(), range2.endPosition());
     Vector<UChar> output2;
-    backIter2.prependTextTo(output2, 0, 2);
+    backIter2.copyTextTo(output2, 0, 2);
     EXPECT_EQ("ro", String(output2)) << String::format(message, 2, "ro").utf8().data();
-    backIter2.prependTextTo(output2, 2, 3);
+    backIter2.copyTextTo(output2, 2, 3);
     EXPECT_EQ(" zero", String(output2)) << String::format(message, 2, " zero").utf8().data();
     backIter2.advance();
-    backIter2.prependTextTo(output2, 0, 1);
+    backIter2.copyTextTo(output2, 0, 1);
     EXPECT_EQ("e zero", String(output2)) << String::format(message, 2, "e zero").utf8().data();
-    backIter2.prependTextTo(output2, 1, 2);
+    backIter2.copyTextTo(output2, 1, 2);
     EXPECT_EQ("one zero", String(output2)) << String::format(message, 2, "one zero").utf8().data();
     backIter2.advance();
-    backIter2.prependTextTo(output2, 0, 1);
+    backIter2.copyTextTo(output2, 0, 1);
     EXPECT_EQ(" one zero", String(output2)) << String::format(message, 2, " one zero").utf8().data();
     backIter2.advance();
-    backIter2.prependTextTo(output2, 0, 2);
+    backIter2.copyTextTo(output2, 0, 2);
     EXPECT_EQ("wo one zero", String(output2)) << String::format(message, 2, "wo one zero").utf8().data();
-    backIter2.prependTextTo(output2, 2, 1);
+    backIter2.copyTextTo(output2, 2, 1);
     EXPECT_EQ("two one zero", String(output2)) << String::format(message, 2, "two one zero").utf8().data();
     backIter2.advance();
-    backIter2.prependTextTo(output2, 0, 3);
+    backIter2.copyTextTo(output2, 0, 3);
     EXPECT_EQ("ee two one zero", String(output2)) << String::format(message, 2, "ee two one zero").utf8().data();
-    backIter2.prependTextTo(output2, 3, 3);
+    backIter2.copyTextTo(output2, 3, 3);
     EXPECT_EQ("three two one zero", String(output2)) << String::format(message, 2, "three two one zero").utf8().data();
 }
 
diff --git a/third_party/WebKit/Source/core/editing/iterators/TextIterator.h b/third_party/WebKit/Source/core/editing/iterators/TextIterator.h
index af1aff4..1262719d 100644
--- a/third_party/WebKit/Source/core/editing/iterators/TextIterator.h
+++ b/third_party/WebKit/Source/core/editing/iterators/TextIterator.h
@@ -78,11 +78,13 @@
 
     bool breaksAtReplacedElement() { return !(m_behavior & TextIteratorDoesNotBreakAtReplacedElement); }
 
+    // Append characters with offset range [position, position + copyLength)
+    // to the output buffer.
     template<typename BufferType>
-    void appendTextTo(BufferType& output, int position = 0) const { appendTextTo(output, position, length() - position); }
+    void copyTextTo(BufferType& output, int position, int copyLength) const { m_textState.appendTextTo(output, position, copyLength); }
 
     template<typename BufferType>
-    void appendTextTo(BufferType& output, int position, int appendLength) const { m_textState.appendTextTo(output, position, appendLength); }
+    void copyTextTo(BufferType& output, int position = 0) const { copyTextTo(output, position, length() - position); }
 
     // Computes the length of the given range using a text iterator. The default
     // iteration behavior is to always emit object replacement characters for
diff --git a/third_party/WebKit/Source/core/editing/iterators/TextIteratorTest.cpp b/third_party/WebKit/Source/core/editing/iterators/TextIteratorTest.cpp
index 36209b6..1d47165 100644
--- a/third_party/WebKit/Source/core/editing/iterators/TextIteratorTest.cpp
+++ b/third_party/WebKit/Source/core/editing/iterators/TextIteratorTest.cpp
@@ -386,7 +386,7 @@
     EXPECT_EQ(3, TextIterator::rangeLength(range->startPosition(), range->endPosition()));
 }
 
-TEST_F(TextIteratorTest, appendTextTo)
+TEST_F(TextIteratorTest, copyTextTo)
 {
     const char* bodyContent = "<a id=host><b id=one>one</b> not appeared <b id=two>two</b></a>";
     const char* shadowContent = "three <content select=#two></content> <content select=#one></content> zero";
@@ -400,40 +400,40 @@
     EphemeralRangeTemplate<EditingStrategy> range1(EphemeralRangeTemplate<EditingStrategy>::rangeOfContents(*host));
     TextIteratorAlgorithm<EditingStrategy> iter1(range1.startPosition(), range1.endPosition());
     Vector<UChar> output1;
-    iter1.appendTextTo(output1, 0, 2);
+    iter1.copyTextTo(output1, 0, 2);
     EXPECT_EQ("on", String(output1)) << String::format(message, 1, "on").utf8().data();
-    iter1.appendTextTo(output1, 2, 1);
+    iter1.copyTextTo(output1, 2, 1);
     EXPECT_EQ("one", String(output1)) << String::format(message, 1, "one").utf8().data();
     iter1.advance();
-    iter1.appendTextTo(output1, 0, 1);
+    iter1.copyTextTo(output1, 0, 1);
     EXPECT_EQ("onet", String(output1)) << String::format(message, 1, "onet").utf8().data();
-    iter1.appendTextTo(output1, 1, 2);
+    iter1.copyTextTo(output1, 1, 2);
     EXPECT_EQ("onetwo", String(output1)) << String::format(message, 1, "onetwo").utf8().data();
 
     EphemeralRangeTemplate<EditingInComposedTreeStrategy> range2(EphemeralRangeTemplate<EditingInComposedTreeStrategy>::rangeOfContents(*host));
     TextIteratorAlgorithm<EditingInComposedTreeStrategy> iter2(range2.startPosition(), range2.endPosition());
     Vector<UChar> output2;
-    iter2.appendTextTo(output2, 0, 3);
+    iter2.copyTextTo(output2, 0, 3);
     EXPECT_EQ("thr", String(output2)) << String::format(message, 2, "thr").utf8().data();
-    iter2.appendTextTo(output2, 3, 3);
+    iter2.copyTextTo(output2, 3, 3);
     EXPECT_EQ("three ", String(output2)) << String::format(message, 2, "three ").utf8().data();
     iter2.advance();
-    iter2.appendTextTo(output2, 0, 2);
+    iter2.copyTextTo(output2, 0, 2);
     EXPECT_EQ("three tw", String(output2)) << String::format(message, 2, "three tw").utf8().data();
-    iter2.appendTextTo(output2, 2, 1);
+    iter2.copyTextTo(output2, 2, 1);
     EXPECT_EQ("three two", String(output2)) << String::format(message, 2, "three two").utf8().data();
     iter2.advance();
-    iter2.appendTextTo(output2, 0, 1);
+    iter2.copyTextTo(output2, 0, 1);
     EXPECT_EQ("three two ", String(output2)) << String::format(message, 2, "three two ").utf8().data();
     iter2.advance();
-    iter2.appendTextTo(output2, 0, 1);
+    iter2.copyTextTo(output2, 0, 1);
     EXPECT_EQ("three two o", String(output2)) << String::format(message, 2, "three two o").utf8().data();
-    iter2.appendTextTo(output2, 1, 2);
+    iter2.copyTextTo(output2, 1, 2);
     EXPECT_EQ("three two one", String(output2)) << String::format(message, 2, "three two one").utf8().data();
     iter2.advance();
-    iter2.appendTextTo(output2, 0, 2);
+    iter2.copyTextTo(output2, 0, 2);
     EXPECT_EQ("three two one z", String(output2)) << String::format(message, 2, "three two one z").utf8().data();
-    iter2.appendTextTo(output2, 2, 3);
+    iter2.copyTextTo(output2, 2, 3);
     EXPECT_EQ("three two one zero", String(output2)) << String::format(message, 2, "three two one zero").utf8().data();
 }
 
diff --git a/third_party/WebKit/Source/core/editing/iterators/WordAwareIterator.cpp b/third_party/WebKit/Source/core/editing/iterators/WordAwareIterator.cpp
index 7b8dc947..0efac79 100644
--- a/third_party/WebKit/Source/core/editing/iterators/WordAwareIterator.cpp
+++ b/third_party/WebKit/Source/core/editing/iterators/WordAwareIterator.cpp
@@ -66,7 +66,7 @@
 
         // If this is the first chunk that failed, save it in m_buffer before look ahead.
         if (m_buffer.isEmpty())
-            m_textIterator.appendTextTo(m_buffer);
+            m_textIterator.copyTextTo(m_buffer);
 
         // Look ahead to next chunk. If it is whitespace or a break, we can use the previous stuff
         m_textIterator.advance();
@@ -76,7 +76,7 @@
         }
 
         // Start gobbling chunks until we get to a suitable stopping point
-        m_textIterator.appendTextTo(m_buffer);
+        m_textIterator.copyTextTo(m_buffer);
     }
 }
 
diff --git a/third_party/WebKit/Source/core/frame/LocalFrame.cpp b/third_party/WebKit/Source/core/frame/LocalFrame.cpp
index eca2f18..900be28 100644
--- a/third_party/WebKit/Source/core/frame/LocalFrame.cpp
+++ b/third_party/WebKit/Source/core/frame/LocalFrame.cpp
@@ -775,15 +775,15 @@
     spellChecker().removeSpellingMarkersUnderWords(words);
 }
 
-static ScrollResult scrollAreaOnBothAxes(const FloatSize& delta, ScrollableArea& view)
+static ScrollResult scrollAreaOnBothAxes(ScrollGranularity granularity, const FloatSize& delta, ScrollableArea& view)
 {
-    ScrollResultOneDimensional scrolledHorizontal = view.userScroll(ScrollLeft, ScrollByPrecisePixel, delta.width());
-    ScrollResultOneDimensional scrolledVertical = view.userScroll(ScrollUp, ScrollByPrecisePixel, delta.height());
+    ScrollResultOneDimensional scrolledHorizontal = view.userScroll(ScrollLeft, granularity, delta.width());
+    ScrollResultOneDimensional scrolledVertical = view.userScroll(ScrollUp, granularity, delta.height());
     return ScrollResult(scrolledHorizontal.didScroll, scrolledVertical.didScroll, scrolledHorizontal.unusedScrollDelta, scrolledVertical.unusedScrollDelta);
 }
 
 // Returns true if a scroll occurred.
-ScrollResult LocalFrame::applyScrollDelta(const FloatSize& delta, bool isScrollBegin)
+ScrollResult LocalFrame::applyScrollDelta(ScrollGranularity granularity, const FloatSize& delta, bool isScrollBegin)
 {
     if (isScrollBegin)
         host()->topControls().scrollBegin();
@@ -800,7 +800,7 @@
     if (remainingDelta.isZero())
         return ScrollResult(delta.width(), delta.height(), 0.0f, 0.0f);
 
-    ScrollResult result = scrollAreaOnBothAxes(remainingDelta, *view()->scrollableArea());
+    ScrollResult result = scrollAreaOnBothAxes(granularity, remainingDelta, *view()->scrollableArea());
     result.didScrollX = result.didScrollX || (remainingDelta.width() != delta.width());
     result.didScrollY = result.didScrollY || (remainingDelta.height() != delta.height());
 
diff --git a/third_party/WebKit/Source/core/frame/LocalFrame.h b/third_party/WebKit/Source/core/frame/LocalFrame.h
index a78868e..27b5471 100644
--- a/third_party/WebKit/Source/core/frame/LocalFrame.h
+++ b/third_party/WebKit/Source/core/frame/LocalFrame.h
@@ -171,7 +171,7 @@
 
     // FIXME: once scroll customization is enabled everywhere
     // (crbug.com/416862), this should take a ScrollState object.
-    ScrollResult applyScrollDelta(const FloatSize& delta, bool isScrollBegin);
+    ScrollResult applyScrollDelta(ScrollGranularity, const FloatSize& delta, bool isScrollBegin);
     bool shouldScrollTopControls(const FloatSize& delta) const;
 
     // DisplayItemClient methods
diff --git a/third_party/WebKit/Source/core/html/HTMLContentElement.cpp b/third_party/WebKit/Source/core/html/HTMLContentElement.cpp
index 36d42a5..77e434d 100644
--- a/third_party/WebKit/Source/core/html/HTMLContentElement.cpp
+++ b/third_party/WebKit/Source/core/html/HTMLContentElement.cpp
@@ -75,8 +75,10 @@
 void HTMLContentElement::parseAttribute(const QualifiedName& name, const AtomicString& oldValue, const AtomicString& value)
 {
     if (name == selectAttr) {
-        if (ShadowRoot* root = containingShadowRoot())
-            root->owner()->willAffectSelector();
+        if (ShadowRoot* root = containingShadowRoot()) {
+            if (root->owner())
+                root->owner()->willAffectSelector();
+        }
         m_shouldParseSelect = true;
         m_select = value;
     } else {
diff --git a/third_party/WebKit/Source/core/input/EventHandler.cpp b/third_party/WebKit/Source/core/input/EventHandler.cpp
index 47861ee8..038faa3 100644
--- a/third_party/WebKit/Source/core/input/EventHandler.cpp
+++ b/third_party/WebKit/Source/core/input/EventHandler.cpp
@@ -2505,7 +2505,11 @@
     if (delta.isZero())
         return WebInputEventResult::NotHandled;
 
+    ScrollGranularity granularity = gestureEvent.deltaUnits();
     Node* node = m_scrollGestureHandlingNode.get();
+
+    // Scroll customization is only available for touch.
+    bool handleScrollCustomization = RuntimeEnabledFeatures::scrollCustomizationEnabled() && gestureEvent.source() == PlatformGestureSourceTouchscreen;
     if (node) {
         LayoutObject* layoutObject = node->layoutObject();
         if (!layoutObject)
@@ -2531,7 +2535,7 @@
         }
 
         bool scrolled = false;
-        if (RuntimeEnabledFeatures::scrollCustomizationEnabled()) {
+        if (handleScrollCustomization) {
             RefPtrWillBeRawPtr<ScrollState> scrollState = ScrollState::create(
                 gestureEvent.deltaX(), gestureEvent.deltaY(),
                 0, gestureEvent.velocityX(), gestureEvent.velocityY(),
@@ -2556,7 +2560,6 @@
                 stopNode = m_previousGestureScrolledNode.get();
 
             // First try to scroll the closest scrollable LayoutBox ancestor of |node|.
-            ScrollGranularity granularity = ScrollByPrecisePixel;
             ScrollResultOneDimensional result = scroll(ScrollLeftIgnoringWritingMode, granularity, node, &stopNode, delta.width());
             bool horizontalScroll = result.didScroll;
             if (!gestureEvent.preventPropagation())
@@ -2576,11 +2579,11 @@
         }
     }
 
-    if (RuntimeEnabledFeatures::scrollCustomizationEnabled())
+    if (handleScrollCustomization)
         return WebInputEventResult::NotHandled;
 
     // Try to scroll the frame view.
-    ScrollResult scrollResult = m_frame->applyScrollDelta(delta, false);
+    ScrollResult scrollResult = m_frame->applyScrollDelta(granularity, delta, false);
     FloatPoint position = FloatPoint(gestureEvent.position().x(), gestureEvent.position().y());
     FloatSize velocity = FloatSize(gestureEvent.velocityX(), gestureEvent.velocityY());
     handleOverscroll(scrollResult, position, velocity);
diff --git a/third_party/WebKit/Source/core/layout/LayoutBlockFlow.cpp b/third_party/WebKit/Source/core/layout/LayoutBlockFlow.cpp
index 72377a66..934c729 100644
--- a/third_party/WebKit/Source/core/layout/LayoutBlockFlow.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutBlockFlow.cpp
@@ -1996,7 +1996,7 @@
 
     // When a portion of the layout tree is being detached, anonymous blocks
     // will be combined as their children are deleted. In this process, the
-    // anonymous block later in the tree is merged into the one preceeding it.
+    // anonymous block later in the tree is merged into the one preceding it.
     // It can happen that the later block (this) contains floats that the
     // previous block (toBlockFlow) did not contain, and thus are not in the
     // floating objects list for toBlockFlow. This can result in toBlockFlow containing
diff --git a/third_party/WebKit/Source/core/layout/LayoutBlockFlowLine.cpp b/third_party/WebKit/Source/core/layout/LayoutBlockFlowLine.cpp
index a1b50a2..973526c3 100644
--- a/third_party/WebKit/Source/core/layout/LayoutBlockFlowLine.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutBlockFlowLine.cpp
@@ -1406,7 +1406,7 @@
                     hasBreakableChar, hasBreak, firstLineMaxWidth, lastLineMaxWidth,
                     childMin, childMax, stripFrontSpaces, styleToUse.direction());
 
-                // This text object will not be layed out, but it may still provide a breaking opportunity.
+                // This text object will not be laid out, but it may still provide a breaking opportunity.
                 if (!hasBreak && !childMax) {
                     if (autoWrap && (hasBreakableStart || hasBreakableEnd)) {
                         minLogicalWidth = std::max(minLogicalWidth, inlineMin);
@@ -1532,8 +1532,8 @@
     // Text truncation kicks in in two cases:
     //     1) If your overflow isn't visible and your text-overflow-mode isn't clip.
     //     2) If you're an anonymous block with a block parent that satisfies #1 that was created
-    //        to accomodate a block that has inline and block children. This excludes parents where
-    //        canCollapseAnonymousBlockChild is false, notabley flex items and grid items.
+    //        to accommodate a block that has inline and block children. This excludes parents where
+    //        canCollapseAnonymousBlockChild is false, notably flex items and grid items.
     // FIXME: CSS3 says that descendants that are clipped must also know how to truncate.  This is insanely
     // difficult to figure out in general (especially in the middle of doing layout), so we only handle the
     // simple case of an anonymous block truncating when it's parent is clipped.
@@ -1912,7 +1912,7 @@
         if (curr->hasEllipsisBox()) {
             curr->clearTruncation();
 
-            // Shift the line back where it belongs if we cannot accomodate an ellipsis.
+            // Shift the line back where it belongs if we cannot accommodate an ellipsis.
             LayoutUnit logicalLeft = logicalLeftOffsetForLine(curr->lineTop(), indentText);
             LayoutUnit availableLogicalWidth = logicalRightOffsetForLine(curr->lineTop(), DoNotIndentText) - logicalLeft;
             LayoutUnit totalLogicalWidth = curr->logicalWidth();
diff --git a/third_party/WebKit/Source/core/layout/LayoutCounter.cpp b/third_party/WebKit/Source/core/layout/LayoutCounter.cpp
index 50635b1b..14a2c72 100644
--- a/third_party/WebKit/Source/core/layout/LayoutCounter.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutCounter.cpp
@@ -184,7 +184,7 @@
     // check this layoutObject, because it may affect the positioning in the tree of our counter.
     LayoutObject* searchEndLayoutObject = previousSiblingOrParent(counterOwner);
     // We check layoutObjects in preOrder from the layoutObject that our counter is attached to
-    // towards the begining of the document for counters with the same identifier as the one
+    // towards the beginning of the document for counters with the same identifier as the one
     // we are trying to find a place for. This is the next layoutObject to be checked.
     LayoutObject* currentLayoutObject = previousInPreOrder(counterOwner);
     previousSibling = nullptr;
@@ -283,7 +283,7 @@
         }
         // This function is designed so that the same test is not done twice in an iteration, except for this one
         // which may be done twice in some cases. Rearranging the decision points though, to accommodate this
-        // performance improvement would create more code duplication than is worthwhile in my oppinion and may further
+        // performance improvement would create more code duplication than is worthwhile in my opinion and may further
         // impede the readability of this already complex algorithm.
         if (previousSiblingProtector)
             currentLayoutObject = previousSiblingOrParent(*currentLayoutObject);
diff --git a/third_party/WebKit/Source/core/layout/LayoutGrid.cpp b/third_party/WebKit/Source/core/layout/LayoutGrid.cpp
index 390a4410..d2c58ba6 100644
--- a/third_party/WebKit/Source/core/layout/LayoutGrid.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutGrid.cpp
@@ -1896,7 +1896,7 @@
     case GridAxisCenter: {
         size_t childEndLine = rowsSpan.resolvedFinalPosition();
         LayoutUnit endOfRow = m_rowPositions[childEndLine];
-        // m_rowPositions include gutters so we need to substract them to get the actual end position for a given
+        // m_rowPositions include gutters so we need to subtract them to get the actual end position for a given
         // row (this does not have to be done for the last track as there are no more m_rowPositions after it)
         if (childEndLine < m_rowPositions.size() - 1)
             endOfRow -= guttersSize(ForRows, 2);
@@ -1928,7 +1928,7 @@
     case GridAxisCenter: {
         size_t childEndLine = columnsSpan.resolvedFinalPosition();
         LayoutUnit endOfColumn = m_columnPositions[childEndLine];
-        // m_columnPositions include gutters so we need to substract them to get the actual end position for a given
+        // m_columnPositions include gutters so we need to subtract them to get the actual end position for a given
         // column (this does not have to be done for the last track as there are no more m_columnPositions after it)
         if (childEndLine < m_columnPositions.size() - 1)
             endOfColumn -= guttersSize(ForRows, 2);
diff --git a/third_party/WebKit/Source/core/layout/LayoutObject.cpp b/third_party/WebKit/Source/core/layout/LayoutObject.cpp
index 505b5a3..553056e5 100644
--- a/third_party/WebKit/Source/core/layout/LayoutObject.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutObject.cpp
@@ -364,7 +364,7 @@
     // - layerTypeRequired() would return true for the <body>, creating a new Layer
     // - when the document is painted, both layers are painted. The <body> layer doesn't
     //   know that it's inside a "hidden SVG subtree", and thus paints, even if it shouldn't.
-    // To avoid the problem alltogether, detect early if we're inside a hidden SVG subtree
+    // To avoid the problem altogether, detect early if we're inside a hidden SVG subtree
     // and stop creating layers at all for these cases - they're not used anyways.
     if (newChild->hasLayer() && !layerCreationAllowedForSubtree())
         toLayoutBoxModelObject(newChild)->layer()->removeOnlyThisLayer();
diff --git a/third_party/WebKit/Source/core/layout/LayoutTable.cpp b/third_party/WebKit/Source/core/layout/LayoutTable.cpp
index ee603278..4d8f741c 100644
--- a/third_party/WebKit/Source/core/layout/LayoutTable.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutTable.cpp
@@ -297,7 +297,7 @@
     }
 
     // Ensure we aren't smaller than our min preferred width. This MUST be done after 'max-width' as
-    // we ignore it if it means we wouldn't accomodate our content.
+    // we ignore it if it means we wouldn't accommodate our content.
     setLogicalWidth(std::max<int>(logicalWidth(), minPreferredLogicalWidth()));
 
     // Ensure we aren't smaller than our min-width style.
@@ -313,7 +313,7 @@
     setMarginStart(marginValues.m_start);
     setMarginEnd(marginValues.m_end);
 
-    // We should NEVER shrink the table below the min-content logical width, or else the table can't accomodate
+    // We should NEVER shrink the table below the min-content logical width, or else the table can't accommodate
     // its own content which doesn't match CSS nor what authors expect.
     // FIXME: When we convert to sub-pixel layout for tables we can remove the int conversion
     // https://code.google.com/p/chromium/issues/detail?id=241198
diff --git a/third_party/WebKit/Source/core/layout/line/InlineFlowBox.cpp b/third_party/WebKit/Source/core/layout/line/InlineFlowBox.cpp
index 886eac9..e429394 100644
--- a/third_party/WebKit/Source/core/layout/line/InlineFlowBox.cpp
+++ b/third_party/WebKit/Source/core/layout/line/InlineFlowBox.cpp
@@ -999,12 +999,11 @@
         prev = curr->prevOnLine();
 
         // Layers will handle hit testing themselves.
-        if (curr->boxModelObject() && curr->boxModelObject().hasSelfPaintingLayer())
-            continue;
-
-        if (curr->nodeAtPoint(result, locationInContainer, accumulatedOffset, lineTop, lineBottom)) {
-            lineLayoutItem().updateHitTestResult(result, locationInContainer.point() - toLayoutSize(accumulatedOffset));
-            return true;
+        if (!curr->boxModelObject() || !curr->boxModelObject().hasSelfPaintingLayer()) {
+            if (curr->nodeAtPoint(result, locationInContainer, accumulatedOffset, lineTop, lineBottom)) {
+                lineLayoutItem().updateHitTestResult(result, locationInContainer.point() - toLayoutSize(accumulatedOffset));
+                return true;
+            }
         }
 
         // If the current inline box's layout object and the previous inline box's layout object are same,
@@ -1012,8 +1011,7 @@
         if (prev && curr->lineLayoutItem() == prev->lineLayoutItem())
             continue;
 
-        // If a parent of the current inline box is a culled inline,
-        // we hit test it before we move the previous inline box.
+        // Hit test the culled inline if necessary.
         LineLayoutItem currLayoutItem = curr->lineLayoutItem();
         while (true) {
             // If the previous inline box is not a descendant of a current inline's parent,
diff --git a/third_party/WebKit/Source/core/layout/line/RootInlineBox.cpp b/third_party/WebKit/Source/core/layout/line/RootInlineBox.cpp
index a60533c3..c51b3d2 100644
--- a/third_party/WebKit/Source/core/layout/line/RootInlineBox.cpp
+++ b/third_party/WebKit/Source/core/layout/line/RootInlineBox.cpp
@@ -300,7 +300,7 @@
     }
 
     // When dealing with bidi text, a non-contiguous selection region is possible.
-    // e.g. The logical text aaaAAAbbb (capitals denote RTL text and non-capitals LTR) is layed out
+    // e.g. The logical text aaaAAAbbb (capitals denote RTL text and non-capitals LTR) is laid out
     // visually as 3 text runs |aaa|bbb|AAA| if we select 4 characters from the start of the text the
     // selection will look like (underline denotes selection):
     // |aaa|bbb|AAA|
diff --git a/third_party/WebKit/Source/core/layout/svg/ReferenceFilterBuilder.cpp b/third_party/WebKit/Source/core/layout/svg/ReferenceFilterBuilder.cpp
index 1f2ea90..ddba2fb 100644
--- a/third_party/WebKit/Source/core/layout/svg/ReferenceFilterBuilder.cpp
+++ b/third_party/WebKit/Source/core/layout/svg/ReferenceFilterBuilder.cpp
@@ -69,7 +69,7 @@
 }
 #endif
 
-PassRefPtrWillBeRawPtr<Filter> ReferenceFilterBuilder::build(float zoom, Element* element, FilterEffect* previousEffect, const ReferenceFilterOperation& filterOperation, const SkPaint* fillPaint, const SkPaint* strokePaint)
+PassRefPtrWillBeRawPtr<Filter> ReferenceFilterBuilder::build(float zoom, Element* element, FilterEffect* previousEffect, const ReferenceFilterOperation& filterOperation, const FloatSize* referenceBoxSize, const SkPaint* fillPaint, const SkPaint* strokePaint)
 {
     TreeScope* treeScope = &element->treeScope();
 
@@ -101,8 +101,12 @@
 
     FloatRect referenceBox;
     if (element->inDocument() && element->layoutObject() && element->layoutObject()->enclosingLayer()) {
-        FloatSize size(element->layoutObject()->enclosingLayer()->physicalBoundingBoxIncludingReflectionAndStackingChildren(LayoutPoint()).size());
-        referenceBox = FloatRect(FloatPoint(), size);
+        if (referenceBoxSize) {
+            referenceBox = FloatRect(FloatPoint(), *referenceBoxSize);
+        } else {
+            FloatSize size(element->layoutObject()->enclosingLayer()->physicalBoundingBoxIncludingReflectionAndStackingChildren(LayoutPoint()).size());
+            referenceBox = FloatRect(FloatPoint(), size);
+        }
     }
     referenceBox.scale(1.0f / zoom);
     FloatRect filterRegion = SVGLengthContext::resolveRectangle<SVGFilterElement>(&filterElement, filterElement.filterUnits()->currentValue()->enumValue(), referenceBox);
diff --git a/third_party/WebKit/Source/core/layout/svg/ReferenceFilterBuilder.h b/third_party/WebKit/Source/core/layout/svg/ReferenceFilterBuilder.h
index 521e7fa..8212c0d 100644
--- a/third_party/WebKit/Source/core/layout/svg/ReferenceFilterBuilder.h
+++ b/third_party/WebKit/Source/core/layout/svg/ReferenceFilterBuilder.h
@@ -44,6 +44,7 @@
 class Filter;
 class FilterEffect;
 class FilterOperation;
+class FloatSize;
 class ReferenceFilterOperation;
 
 class ReferenceFilterBuilder {
@@ -55,7 +56,7 @@
     static void clearDocumentResourceReference(const FilterOperation*);
 #endif
 
-    static PassRefPtrWillBeRawPtr<Filter> build(float zoom, Element*, FilterEffect* previousEffect, const ReferenceFilterOperation&, const SkPaint* fillPaint = nullptr, const SkPaint* strokePaint = nullptr);
+    static PassRefPtrWillBeRawPtr<Filter> build(float zoom, Element*, FilterEffect* previousEffect, const ReferenceFilterOperation&, const FloatSize* referenceBoxSize = nullptr, const SkPaint* fillPaint = nullptr, const SkPaint* strokePaint = nullptr);
 };
 
 }
diff --git a/third_party/WebKit/Source/core/page/scrolling/ScrollingCoordinator.cpp b/third_party/WebKit/Source/core/page/scrolling/ScrollingCoordinator.cpp
index 3903651d..ccfd74e 100644
--- a/third_party/WebKit/Source/core/page/scrolling/ScrollingCoordinator.cpp
+++ b/third_party/WebKit/Source/core/page/scrolling/ScrollingCoordinator.cpp
@@ -344,7 +344,7 @@
     if (!platformSupportsCoordinatedScrollbar) {
         if (scrollbarGraphicsLayer) {
             WebLayer* scrollbarLayer = toWebLayer(scrollbarGraphicsLayer);
-            scrollbarLayer->setShouldScrollOnMainThread(true);
+            scrollbarLayer->addMainThreadScrollingReasons(WebMainThreadScrollingReason::ScrollBarScrolling);
         }
         return;
     }
@@ -399,7 +399,7 @@
         // to set the WebLayer's scroll position at fractional precision otherwise the
         // WebLayer's position after snapping to device pixel can be off with regard to
         // fixed position elements.
-        if (m_lastMainThreadScrollingReasons & ScrollingCoordinator::HasNonLayerViewportConstrainedObjects) {
+        if (m_lastMainThreadScrollingReasons & WebMainThreadScrollingReason::HasNonLayerViewportConstrainedObjects) {
             webLayer->setScrollPositionDouble(DoublePoint(scrollableArea->scrollPosition() - scrollableArea->minimumScrollPosition()));
         } else {
             DoublePoint scrollPosition(scrollableArea->scrollPositionDouble() - scrollableArea->minimumScrollPositionDouble());
@@ -714,7 +714,10 @@
         return;
     if (WebLayer* scrollLayer = toWebLayer(m_page->deprecatedLocalMainFrame()->view()->layerForScrolling())) {
         m_lastMainThreadScrollingReasons = reasons;
-        scrollLayer->setShouldScrollOnMainThread(reasons);
+        if (reasons)
+            scrollLayer->addMainThreadScrollingReasons(static_cast<WebMainThreadScrollingReason::WebMainThreadScrollingReason>(reasons));
+        else
+            scrollLayer->clearMainThreadScrollingReasons();
     }
 }
 
@@ -1023,7 +1026,7 @@
     MainThreadScrollingReasons reasons = static_cast<MainThreadScrollingReasons>(0);
 
     if (!m_page->settings().threadedScrollingEnabled())
-        reasons |= ThreadedScrollingDisabled;
+        reasons |= WebMainThreadScrollingReason::ThreadedScrollingDisabled;
 
     if (!m_page->mainFrame()->isLocalFrame())
         return reasons;
@@ -1032,7 +1035,7 @@
         return reasons;
 
     if (frameView->hasBackgroundAttachmentFixedObjects())
-        reasons |= HasBackgroundAttachmentFixedObjects;
+        reasons |= WebMainThreadScrollingReason::HasBackgroundAttachmentFixedObjects;
     FrameView::ScrollingReasons scrollingReasons = frameView->scrollingReasons();
     const bool mayBeScrolledByInput = (scrollingReasons == FrameView::Scrollable);
     const bool mayBeScrolledByScript = mayBeScrolledByInput || (scrollingReasons ==
@@ -1043,7 +1046,7 @@
     // not let this move there path as an optimization, when we have slow-repaint
     // elements.
     if (mayBeScrolledByScript && hasVisibleSlowRepaintViewportConstrainedObjects(frameView)) {
-        reasons |= HasNonLayerViewportConstrainedObjects;
+        reasons |= WebMainThreadScrollingReason::HasNonLayerViewportConstrainedObjects;
     }
 
     return reasons;
@@ -1053,11 +1056,11 @@
 {
     StringBuilder stringBuilder;
 
-    if (reasons & ScrollingCoordinator::HasBackgroundAttachmentFixedObjects)
+    if (reasons & WebMainThreadScrollingReason::HasBackgroundAttachmentFixedObjects)
         stringBuilder.appendLiteral("Has background-attachment:fixed, ");
-    if (reasons & ScrollingCoordinator::HasNonLayerViewportConstrainedObjects)
+    if (reasons & WebMainThreadScrollingReason::HasNonLayerViewportConstrainedObjects)
         stringBuilder.appendLiteral("Has non-layer viewport-constrained objects, ");
-    if (reasons & ScrollingCoordinator::ThreadedScrollingDisabled)
+    if (reasons & WebMainThreadScrollingReason::ThreadedScrollingDisabled)
         stringBuilder.appendLiteral("Threaded scrolling is disabled, ");
 
     if (stringBuilder.length())
diff --git a/third_party/WebKit/Source/core/page/scrolling/ScrollingCoordinator.h b/third_party/WebKit/Source/core/page/scrolling/ScrollingCoordinator.h
index 2b55d1f..fd48d40 100644
--- a/third_party/WebKit/Source/core/page/scrolling/ScrollingCoordinator.h
+++ b/third_party/WebKit/Source/core/page/scrolling/ScrollingCoordinator.h
@@ -31,6 +31,7 @@
 #include "platform/PlatformWheelEvent.h"
 #include "platform/geometry/IntRect.h"
 #include "platform/scroll/ScrollTypes.h"
+#include "public/platform/WebMainThreadScrollingReason.h"
 #include "wtf/Noncopyable.h"
 #include "wtf/text/WTFString.h"
 
@@ -95,12 +96,6 @@
     void handleWheelEventPhase(PlatformWheelEventPhase);
 #endif
 
-    enum MainThreadScrollingReasonFlags {
-        HasBackgroundAttachmentFixedObjects = 1 << 0,
-        HasNonLayerViewportConstrainedObjects = 1 << 1,
-        ThreadedScrollingDisabled = 1 << 2
-    };
-
     MainThreadScrollingReasons mainThreadScrollingReasons() const;
     bool shouldUpdateScrollLayerPositionOnMainThread() const { return mainThreadScrollingReasons() != 0; }
 
diff --git a/third_party/WebKit/Source/core/paint/FilterEffectBuilder.cpp b/third_party/WebKit/Source/core/paint/FilterEffectBuilder.cpp
index faabeec4..f183593 100644
--- a/third_party/WebKit/Source/core/paint/FilterEffectBuilder.cpp
+++ b/third_party/WebKit/Source/core/paint/FilterEffectBuilder.cpp
@@ -130,7 +130,7 @@
     visitor->trace(m_referenceFilters);
 }
 
-bool FilterEffectBuilder::build(Element* element, const FilterOperations& operations, float zoom, const SkPaint* fillPaint, const SkPaint* strokePaint)
+bool FilterEffectBuilder::build(Element* element, const FilterOperations& operations, float zoom, const FloatSize* referenceBoxSize, const SkPaint* fillPaint, const SkPaint* strokePaint)
 {
     // Create a parent filter for shorthand filters. These have already been scaled by the CSS code for page zoom, so scale is 1.0 here.
     RefPtrWillBeRawPtr<Filter> parentFilter = Filter::create(1.0f);
@@ -140,7 +140,7 @@
         FilterOperation* filterOperation = operations.operations().at(i).get();
         switch (filterOperation->type()) {
         case FilterOperation::REFERENCE: {
-            RefPtrWillBeRawPtr<Filter> referenceFilter = ReferenceFilterBuilder::build(zoom, element, previousEffect.get(), toReferenceFilterOperation(*filterOperation), fillPaint, strokePaint);
+            RefPtrWillBeRawPtr<Filter> referenceFilter = ReferenceFilterBuilder::build(zoom, element, previousEffect.get(), toReferenceFilterOperation(*filterOperation), referenceBoxSize, fillPaint, strokePaint);
             if (referenceFilter) {
                 effect = referenceFilter->lastEffect();
                 m_referenceFilters.append(referenceFilter);
diff --git a/third_party/WebKit/Source/core/paint/FilterEffectBuilder.h b/third_party/WebKit/Source/core/paint/FilterEffectBuilder.h
index 6e8da7b9..9022ddf 100644
--- a/third_party/WebKit/Source/core/paint/FilterEffectBuilder.h
+++ b/third_party/WebKit/Source/core/paint/FilterEffectBuilder.h
@@ -53,7 +53,7 @@
     virtual ~FilterEffectBuilder();
     DECLARE_TRACE();
 
-    bool build(Element*, const FilterOperations&, float zoom, const SkPaint* fillPaint = nullptr, const SkPaint* strokePaint = nullptr);
+    bool build(Element*, const FilterOperations&, float zoom, const FloatSize* referenceBoxSize = nullptr, const SkPaint* fillPaint = nullptr, const SkPaint* strokePaint = nullptr);
 
     PassRefPtrWillBeRawPtr<FilterEffect> lastEffect() const
     {
diff --git a/third_party/WebKit/Source/modules/canvas2d/CanvasRenderingContext2D.cpp b/third_party/WebKit/Source/modules/canvas2d/CanvasRenderingContext2D.cpp
index 8cf6c194..c2b01b6 100644
--- a/third_party/WebKit/Source/modules/canvas2d/CanvasRenderingContext2D.cpp
+++ b/third_party/WebKit/Source/modules/canvas2d/CanvasRenderingContext2D.cpp
@@ -828,7 +828,7 @@
 template<typename DrawFunc>
 void CanvasRenderingContext2D::compositedDraw(const DrawFunc& drawFunc, SkCanvas* c, CanvasRenderingContext2DState::PaintType paintType, CanvasRenderingContext2DState::ImageType imageType)
 {
-    SkImageFilter* filter = state().getFilter(canvas(), accessFont());
+    SkImageFilter* filter = state().getFilter(canvas(), accessFont(), canvas()->size());
     ASSERT(isFullCanvasCompositeMode(state().globalComposite()) || filter);
     SkMatrix ctm = c->getTotalMatrix();
     c->resetMatrix();
diff --git a/third_party/WebKit/Source/modules/canvas2d/CanvasRenderingContext2DState.cpp b/third_party/WebKit/Source/modules/canvas2d/CanvasRenderingContext2DState.cpp
index 71f1564c..09b50bd5 100644
--- a/third_party/WebKit/Source/modules/canvas2d/CanvasRenderingContext2DState.cpp
+++ b/third_party/WebKit/Source/modules/canvas2d/CanvasRenderingContext2DState.cpp
@@ -341,7 +341,7 @@
     m_isTransformInvertible = true;
 }
 
-SkImageFilter* CanvasRenderingContext2DState::getFilter(Element* styleResolutionHost, const Font& font) const
+SkImageFilter* CanvasRenderingContext2DState::getFilter(Element* styleResolutionHost, const Font& font, IntSize canvasSize) const
 {
     if (!m_filterValue)
         return nullptr;
@@ -365,8 +365,9 @@
         m_strokeStyle->applyToPaint(strokePaintForFilter);
         fillPaintForFilter.setColor(m_fillStyle->paintColor());
         strokePaintForFilter.setColor(m_strokeStyle->paintColor());
+        FloatSize floatCanvasSize(canvasSize);
         const double effectiveZoom = 1.0; // Deliberately ignore zoom on the canvas element
-        filterEffectBuilder->build(styleResolutionHost, filterStyle->filter(), effectiveZoom, &fillPaintForFilter, &strokePaintForFilter);
+        filterEffectBuilder->build(styleResolutionHost, filterStyle->filter(), effectiveZoom, &floatCanvasSize, &fillPaintForFilter, &strokePaintForFilter);
 
         SkiaImageFilterBuilder imageFilterBuilder;
         RefPtrWillBeRawPtr<FilterEffect> lastEffect = filterEffectBuilder->lastEffect();
diff --git a/third_party/WebKit/Source/modules/canvas2d/CanvasRenderingContext2DState.h b/third_party/WebKit/Source/modules/canvas2d/CanvasRenderingContext2DState.h
index 326700a..df13ac9 100644
--- a/third_party/WebKit/Source/modules/canvas2d/CanvasRenderingContext2DState.h
+++ b/third_party/WebKit/Source/modules/canvas2d/CanvasRenderingContext2DState.h
@@ -84,7 +84,7 @@
     void setFilter(PassRefPtrWillBeRawPtr<CSSValue>);
     void setUnparsedFilter(const String& filterString) { m_unparsedFilter = filterString; }
     const String& unparsedFilter() const { return m_unparsedFilter; }
-    SkImageFilter* getFilter(Element*, const Font&) const;
+    SkImageFilter* getFilter(Element*, const Font&, IntSize canvasSize) const;
     bool hasFilter() const { return m_filterValue; }
 
     void setStrokeStyle(CanvasStyle*);
diff --git a/third_party/WebKit/Source/modules/serviceworkers/FetchEvent.cpp b/third_party/WebKit/Source/modules/serviceworkers/FetchEvent.cpp
index 7ece4b9..785e1e5 100644
--- a/third_party/WebKit/Source/modules/serviceworkers/FetchEvent.cpp
+++ b/third_party/WebKit/Source/modules/serviceworkers/FetchEvent.cpp
@@ -30,6 +30,11 @@
     return m_request;
 }
 
+String FetchEvent::clientId() const
+{
+    return m_clientId;
+}
+
 bool FetchEvent::isReload() const
 {
     return m_isReload;
@@ -57,6 +62,7 @@
 {
     if (initializer.hasRequest())
         m_request = initializer.request();
+    m_clientId = initializer.clientId();
     m_isReload = initializer.isReload();
 }
 
diff --git a/third_party/WebKit/Source/modules/serviceworkers/FetchEvent.h b/third_party/WebKit/Source/modules/serviceworkers/FetchEvent.h
index 1b4d19a..793c5cd 100644
--- a/third_party/WebKit/Source/modules/serviceworkers/FetchEvent.h
+++ b/third_party/WebKit/Source/modules/serviceworkers/FetchEvent.h
@@ -31,6 +31,7 @@
     static PassRefPtrWillBeRawPtr<FetchEvent> create(const AtomicString& type, const FetchEventInit&, RespondWithObserver*);
 
     Request* request() const;
+    String clientId() const;
     bool isReload() const;
 
     void respondWith(ScriptState*, ScriptPromise, ExceptionState&);
@@ -46,6 +47,7 @@
 private:
     PersistentWillBeMember<RespondWithObserver> m_observer;
     PersistentWillBeMember<Request> m_request;
+    String m_clientId;
     bool m_isReload;
 };
 
diff --git a/third_party/WebKit/Source/modules/serviceworkers/FetchEvent.idl b/third_party/WebKit/Source/modules/serviceworkers/FetchEvent.idl
index 817554a..e8f4551d 100644
--- a/third_party/WebKit/Source/modules/serviceworkers/FetchEvent.idl
+++ b/third_party/WebKit/Source/modules/serviceworkers/FetchEvent.idl
@@ -4,10 +4,11 @@
 
 // https://slightlyoff.github.io/ServiceWorker/spec/service_worker/index.html#fetch-event-interface
 [
-    Constructor(DOMString type, optional FetchEventInit eventInitDict),
+    Constructor(DOMString type, FetchEventInit eventInitDict),
     Exposed=ServiceWorker,
 ] interface FetchEvent : ExtendableEvent {
-    readonly attribute Request request;
+    [SameObject] readonly attribute Request request;
+    readonly attribute DOMString? clientId;
     readonly attribute boolean isReload;
 
     [CallWith=ScriptState, RaisesException] void respondWith(Promise<Response> r);
diff --git a/third_party/WebKit/Source/modules/serviceworkers/FetchEventInit.idl b/third_party/WebKit/Source/modules/serviceworkers/FetchEventInit.idl
index cac8bbeb..80da60fd 100644
--- a/third_party/WebKit/Source/modules/serviceworkers/FetchEventInit.idl
+++ b/third_party/WebKit/Source/modules/serviceworkers/FetchEventInit.idl
@@ -5,6 +5,7 @@
 // https://slightlyoff.github.io/ServiceWorker/spec/service_worker/index.html#fetch-event-interface
 
 dictionary FetchEventInit : ExtendableEventInit {
-  Request request;
-  boolean isReload = false;    
+  required Request request;
+  DOMString? clientId = null;
+  boolean isReload = false;
 };
diff --git a/third_party/WebKit/Source/modules/websockets/DOMWebSocket.cpp b/third_party/WebKit/Source/modules/websockets/DOMWebSocket.cpp
index 524798b..48cfa5e 100644
--- a/third_party/WebKit/Source/modules/websockets/DOMWebSocket.cpp
+++ b/third_party/WebKit/Source/modules/websockets/DOMWebSocket.cpp
@@ -446,9 +446,17 @@
         return;
     }
     Platform::current()->histogramEnumeration("WebCore.WebSocket.SendType", WebSocketSendTypeBlob, WebSocketSendTypeMax);
-    m_bufferedAmount += binaryData->size();
+    unsigned long long size = binaryData->size();
+    m_bufferedAmount += size;
     ASSERT(m_channel);
-    m_channel->send(binaryData->blobDataHandle());
+
+    // When the runtime type of |binaryData| is File,
+    // binaryData->blobDataHandle()->size() returns -1. However, in order to
+    // maintain the value of |m_bufferedAmount| correctly, the WebSocket code
+    // needs to fix the size of the File at this point. For this reason,
+    // construct a new BlobDataHandle here with the size that this method
+    // observed.
+    m_channel->send(BlobDataHandle::create(binaryData->uuid(), binaryData->type(), size));
 }
 
 void DOMWebSocket::close(unsigned short code, const String& reason, ExceptionState& exceptionState)
diff --git a/third_party/WebKit/Source/platform/EventTracer.cpp b/third_party/WebKit/Source/platform/EventTracer.cpp
index 30a8f11..08469ce 100644
--- a/third_party/WebKit/Source/platform/EventTracer.cpp
+++ b/third_party/WebKit/Source/platform/EventTracer.cpp
@@ -31,17 +31,45 @@
 #include "platform/EventTracer.h"
 
 #include "base/time/time.h"
+#include "base/trace_event/trace_event.h"
 #include "public/platform/Platform.h"
-#include "public/platform/WebConvertableToTraceFormat.h"
 #include "wtf/Assertions.h"
+#include "wtf/text/StringUTF8Adaptor.h"
 #include <stdio.h>
 
 namespace blink {
 
-static_assert(sizeof(Platform::TraceEventHandle) == sizeof(TraceEvent::TraceEventHandle), "TraceEventHandle types must be compatible");
-static_assert(sizeof(Platform::TraceEventAPIAtomicWord) == sizeof(TraceEvent::TraceEventAPIAtomicWord), "TraceEventAPIAtomicWord types must be compatible");
+static_assert(sizeof(TraceEvent::TraceEventHandle) == sizeof(base::trace_event::TraceEventHandle), "TraceEventHandle types must be the same");
 static_assert(sizeof(TraceEvent::TraceEventAPIAtomicWord) == sizeof(const char*), "TraceEventAPIAtomicWord must be pointer-sized.");
 
+namespace {
+
+class ConvertableToTraceFormatWrapper : public base::trace_event::ConvertableToTraceFormat {
+public:
+    // We move a reference pointer from |convertable| to |m_convertable|,
+    // rather than copying, for thread safety. https://crbug.com/478149
+    explicit ConvertableToTraceFormatWrapper(PassRefPtr<blink::TraceEvent::ConvertableToTraceFormat> convertable)
+        : m_convertable(convertable)
+    {
+        ASSERT(m_convertable);
+    }
+    void AppendAsTraceFormat(std::string* out) const override
+    {
+        // TODO(bashi): Avoid copying.
+        String traceFormat = m_convertable->asTraceFormat();
+        StringUTF8Adaptor utf8(traceFormat);
+        out->append(utf8.data(), utf8.length());
+    }
+    // TODO(bashi): Override EstimateTraceMemoryOverhead()
+
+private:
+    ~ConvertableToTraceFormatWrapper() override {}
+
+    RefPtr<blink::TraceEvent::ConvertableToTraceFormat> m_convertable;
+};
+
+} // namespace
+
 // The dummy variable is needed to avoid a crash when someone updates the state variables
 // before EventTracer::initialize() is called.
 TraceEvent::TraceEventAPIAtomicWord dummyTraceSamplingState = 0;
@@ -49,30 +77,21 @@
 
 void EventTracer::initialize()
 {
-    // current() might not exist in unit tests.
-    if (!Platform::current())
-        return;
-
-    traceSamplingState[0] = Platform::current()->getTraceSamplingState(0);
+    traceSamplingState[0] = reinterpret_cast<TraceEvent::TraceEventAPIAtomicWord*>(&TRACE_EVENT_API_THREAD_BUCKET(0));
     // FIXME: traceSamplingState[0] can be 0 in split-dll build. http://crbug.com/256965
     if (!traceSamplingState[0])
         traceSamplingState[0] = &dummyTraceSamplingState;
-    traceSamplingState[1] = Platform::current()->getTraceSamplingState(1);
+    traceSamplingState[1] = reinterpret_cast<TraceEvent::TraceEventAPIAtomicWord*>(&TRACE_EVENT_API_THREAD_BUCKET(1));
     if (!traceSamplingState[1])
         traceSamplingState[1] = &dummyTraceSamplingState;
-    traceSamplingState[2] = Platform::current()->getTraceSamplingState(2);
+    traceSamplingState[2] = reinterpret_cast<TraceEvent::TraceEventAPIAtomicWord*>(&TRACE_EVENT_API_THREAD_BUCKET(2));
     if (!traceSamplingState[2])
         traceSamplingState[2] = &dummyTraceSamplingState;
 }
 
 const unsigned char* EventTracer::getTraceCategoryEnabledFlag(const char* categoryName)
 {
-    static const char* dummyCategoryEnabledFlag = "*";
-    // current() might not exist in unit tests.
-    if (!Platform::current())
-        return reinterpret_cast<const unsigned char*>(dummyCategoryEnabledFlag);
-
-    return Platform::current()->getTraceCategoryEnabledFlag(categoryName);
+    return TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED(categoryName);
 }
 
 TraceEvent::TraceEventHandle EventTracer::addTraceEvent(char phase, const unsigned char* categoryEnabledFlag,
@@ -83,10 +102,13 @@
     PassRefPtr<TraceEvent::ConvertableToTraceFormat> convertableValue2,
     unsigned flags)
 {
-    WebConvertableToTraceFormat webConvertableValues[2];
-    webConvertableValues[0] = WebConvertableToTraceFormat(convertableValue1);
-    webConvertableValues[1] = WebConvertableToTraceFormat(convertableValue2);
-    return Platform::current()->addTraceEvent(phase, categoryEnabledFlag, name, id, bindId, timestamp, numArgs, argNames, argTypes, argValues, webConvertableValues, flags);
+    scoped_refptr<base::trace_event::ConvertableToTraceFormat> wrappers[2];
+    ASSERT(numArgs <= 2);
+    if (numArgs >= 1 && argTypes[0] == TRACE_VALUE_TYPE_CONVERTABLE)
+        wrappers[0] = new ConvertableToTraceFormatWrapper(convertableValue1);
+    if (numArgs >= 2 && argTypes[1] == TRACE_VALUE_TYPE_CONVERTABLE)
+        wrappers[1] = new ConvertableToTraceFormatWrapper(convertableValue2);
+    return addTraceEvent(phase, categoryEnabledFlag, name, id, bindId, timestamp, numArgs, argNames, argTypes, argValues, wrappers, flags);
 }
 
 TraceEvent::TraceEventHandle EventTracer::addTraceEvent(char phase, const unsigned char* categoryEnabledFlag,
@@ -94,12 +116,26 @@
     int numArgs, const char** argNames, const unsigned char* argTypes,
     const unsigned long long* argValues, unsigned flags)
 {
-    return Platform::current()->addTraceEvent(phase, categoryEnabledFlag, name, id, bindId, timestamp, numArgs, argNames, argTypes, argValues, 0, flags);
+    return addTraceEvent(phase, categoryEnabledFlag, name, id, bindId, timestamp, numArgs, argNames, argTypes, argValues, nullptr, flags);
+}
+
+TraceEvent::TraceEventHandle EventTracer::addTraceEvent(char phase, const unsigned char* categoryEnabledFlag,
+    const char* name, unsigned long long id, unsigned long long bindId, double timestamp,
+    int numArgs, const char** argNames, const unsigned char* argTypes, const unsigned long long* argValues,
+    const scoped_refptr<base::trace_event::ConvertableToTraceFormat>* convertables, unsigned flags)
+{
+    base::TimeTicks timestampTimeTicks = base::TimeTicks() + base::TimeDelta::FromSecondsD(timestamp);
+    base::trace_event::TraceEventHandle handle = TRACE_EVENT_API_ADD_TRACE_EVENT_WITH_THREAD_ID_AND_TIMESTAMP(phase, categoryEnabledFlag, name, id, bindId, base::PlatformThread::CurrentId(), timestampTimeTicks, numArgs, argNames, argTypes, argValues, convertables, flags);
+    TraceEvent::TraceEventHandle result;
+    memcpy(&result, &handle, sizeof(result));
+    return result;
 }
 
 void EventTracer::updateTraceEventDuration(const unsigned char* categoryEnabledFlag, const char* name, TraceEvent::TraceEventHandle handle)
 {
-    Platform::current()->updateTraceEventDuration(categoryEnabledFlag, name, handle);
+    base::trace_event::TraceEventHandle traceEventHandle;
+    memcpy(&traceEventHandle, &handle, sizeof(handle));
+    TRACE_EVENT_API_UPDATE_TRACE_EVENT_DURATION(categoryEnabledFlag, name, traceEventHandle);
 }
 
 double EventTracer::systemTraceTime()
diff --git a/third_party/WebKit/Source/platform/EventTracer.h b/third_party/WebKit/Source/platform/EventTracer.h
index e6d4b4b2..4b5ec04b 100644
--- a/third_party/WebKit/Source/platform/EventTracer.h
+++ b/third_party/WebKit/Source/platform/EventTracer.h
@@ -31,6 +31,7 @@
 #ifndef EventTracer_h
 #define EventTracer_h
 
+#include "base/memory/ref_counted.h"
 #include "platform/PlatformExport.h"
 #include "wtf/Allocator.h"
 #include "wtf/RefCounted.h"
@@ -39,6 +40,12 @@
 
 #include <stdint.h>
 
+namespace base {
+namespace trace_event {
+class ConvertableToTraceFormat;
+}
+}
+
 // This will mark the trace event as disabled by default. The user will need
 // to explicitly enable the event.
 #define TRACE_DISABLED_BY_DEFAULT(name) "disabled-by-default-" name
@@ -91,6 +98,20 @@
         unsigned flags);
     static void updateTraceEventDuration(const unsigned char* categoryEnabledFlag, const char* name, TraceEvent::TraceEventHandle);
     static double systemTraceTime();
+
+private:
+    static TraceEvent::TraceEventHandle addTraceEvent(char phase,
+        const unsigned char* categoryEnabledFlag,
+        const char* name,
+        unsigned long long id,
+        unsigned long long bindId,
+        double timestamp,
+        int numArgs,
+        const char* argNames[],
+        const unsigned char argTypes[],
+        const unsigned long long argValues[],
+        const scoped_refptr<base::trace_event::ConvertableToTraceFormat>* convertables,
+        unsigned flags);
 };
 
 } // namespace blink
diff --git a/third_party/WebKit/Source/platform/PlatformGestureEvent.h b/third_party/WebKit/Source/platform/PlatformGestureEvent.h
index 57d5ef7b..a9a1072 100644
--- a/third_party/WebKit/Source/platform/PlatformGestureEvent.h
+++ b/third_party/WebKit/Source/platform/PlatformGestureEvent.h
@@ -30,6 +30,7 @@
 #include "platform/geometry/FloatPoint.h"
 #include "platform/geometry/IntPoint.h"
 #include "platform/geometry/IntSize.h"
+#include "platform/scroll/ScrollTypes.h"
 #include "wtf/Assertions.h"
 #include <string.h>
 
@@ -62,7 +63,7 @@
         memset(&m_data, 0, sizeof(m_data));
     }
 
-    void setScrollGestureData(float deltaX, float deltaY, float velocityX, float velocityY,
+    void setScrollGestureData(float deltaX, float deltaY, ScrollGranularity deltaUnits, float velocityX, float velocityY,
         bool inertial, bool preventPropagation, int resendingPluginId)
     {
         ASSERT(type() == PlatformEvent::GestureScrollBegin
@@ -81,6 +82,7 @@
 
         m_data.m_scroll.m_deltaX = deltaX;
         m_data.m_scroll.m_deltaY = deltaY;
+        m_data.m_scroll.m_deltaUnits = deltaUnits;
         m_data.m_scroll.m_velocityX = velocityX;
         m_data.m_scroll.m_velocityY = velocityY;
         m_data.m_scroll.m_inertial = inertial;
@@ -107,6 +109,12 @@
         return m_data.m_scroll.m_deltaY;
     }
 
+    ScrollGranularity deltaUnits() const
+    {
+        ASSERT(m_type == PlatformEvent::GestureScrollUpdate);
+        return m_data.m_scroll.m_deltaUnits;
+    }
+
     int tapCount() const
     {
         ASSERT(m_type == PlatformEvent::GestureTap);
@@ -212,6 +220,7 @@
             float m_velocityY;
             int m_preventPropagation;
             bool m_inertial;
+            ScrollGranularity m_deltaUnits;
             int m_resendingPluginId;
         } m_scroll;
 
diff --git a/third_party/WebKit/Source/platform/blink_platform.gypi b/third_party/WebKit/Source/platform/blink_platform.gypi
index 49ea34b..9dec2b0 100644
--- a/third_party/WebKit/Source/platform/blink_platform.gypi
+++ b/third_party/WebKit/Source/platform/blink_platform.gypi
@@ -272,7 +272,6 @@
       'exported/WebContentDecryptionModuleResult.cpp',
       'exported/WebContentDecryptionModuleSession.cpp',
       'exported/WebContentSettingCallbacks.cpp',
-      'exported/WebConvertableToTraceFormat.cpp',
       'exported/WebCredential.cpp',
       'exported/WebCryptoAlgorithm.cpp',
       'exported/WebCryptoKey.cpp',
diff --git a/third_party/WebKit/Source/platform/exported/WebConvertableToTraceFormat.cpp b/third_party/WebKit/Source/platform/exported/WebConvertableToTraceFormat.cpp
deleted file mode 100644
index dca9367..0000000
--- a/third_party/WebKit/Source/platform/exported/WebConvertableToTraceFormat.cpp
+++ /dev/null
@@ -1,37 +0,0 @@
-// Copyright 2014 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 "public/platform/WebConvertableToTraceFormat.h"
-
-#include "platform/EventTracer.h"
-#include "public/platform/WebString.h"
-
-namespace blink {
-
-WebConvertableToTraceFormat::WebConvertableToTraceFormat(PassRefPtr<TraceEvent::ConvertableToTraceFormat> convertable)
-    : m_private(convertable)
-{
-}
-
-WebString WebConvertableToTraceFormat::asTraceFormat() const
-{
-    return m_private->asTraceFormat();
-}
-
-void WebConvertableToTraceFormat::assign(const WebConvertableToTraceFormat& r)
-{
-    m_private = r.m_private;
-}
-
-void WebConvertableToTraceFormat::moveFrom(WebConvertableToTraceFormat& r)
-{
-    m_private.moveFrom(r.m_private);
-}
-
-void WebConvertableToTraceFormat::reset()
-{
-    m_private.reset();
-}
-
-} // namespace blink
diff --git a/third_party/WebKit/Source/platform/exported/WebServiceWorkerRequest.cpp b/third_party/WebKit/Source/platform/exported/WebServiceWorkerRequest.cpp
index bc9c6ed9..95bce10b 100644
--- a/third_party/WebKit/Source/platform/exported/WebServiceWorkerRequest.cpp
+++ b/third_party/WebKit/Source/platform/exported/WebServiceWorkerRequest.cpp
@@ -7,6 +7,7 @@
 #include "platform/blob/BlobData.h"
 #include "platform/weborigin/KURL.h"
 #include "public/platform/WebHTTPHeaderVisitor.h"
+#include "public/platform/WebString.h"
 #include "public/platform/WebURLRequest.h"
 
 namespace blink {
@@ -15,10 +16,12 @@
 public:
     WebServiceWorkerRequestPrivate()
         : m_mode(WebURLRequest::FetchRequestModeNoCORS)
+        , m_isMainResourceLoad(false)
         , m_credentialsMode(WebURLRequest::FetchCredentialsModeOmit)
         , m_redirectMode(WebURLRequest::FetchRedirectModeFollow)
         , m_requestContext(WebURLRequest::RequestContextUnspecified)
         , m_frameType(WebURLRequest::FrameTypeNone)
+        , m_clientId(WebString())
         , m_isReload(false)
     {
     }
@@ -28,10 +31,12 @@
     RefPtr<BlobDataHandle> blobDataHandle;
     Referrer m_referrer;
     WebURLRequest::FetchRequestMode m_mode;
+    bool m_isMainResourceLoad;
     WebURLRequest::FetchCredentialsMode m_credentialsMode;
     WebURLRequest::FetchRedirectMode m_redirectMode;
     WebURLRequest::RequestContext m_requestContext;
     WebURLRequest::FrameType m_frameType;
+    WebString m_clientId;
     bool m_isReload;
 };
 
@@ -137,6 +142,16 @@
     return m_private->m_mode;
 }
 
+void WebServiceWorkerRequest::setIsMainResourceLoad(bool isMainResourceLoad)
+{
+    m_private->m_isMainResourceLoad = isMainResourceLoad;
+}
+
+bool WebServiceWorkerRequest::isMainResourceLoad() const
+{
+    return m_private->m_isMainResourceLoad;
+}
+
 void WebServiceWorkerRequest::setCredentialsMode(WebURLRequest::FetchCredentialsMode credentialsMode)
 {
     m_private->m_credentialsMode = credentialsMode;
@@ -177,6 +192,16 @@
     return m_private->m_frameType;
 }
 
+void WebServiceWorkerRequest::setClientId(const WebString& clientId)
+{
+    m_private->m_clientId = clientId;
+}
+
+WebString WebServiceWorkerRequest::clientId() const
+{
+    return m_private->m_clientId;
+}
+
 void WebServiceWorkerRequest::setIsReload(bool isReload)
 {
     m_private->m_isReload = isReload;
diff --git a/third_party/WebKit/Source/platform/fonts/Font.cpp b/third_party/WebKit/Source/platform/fonts/Font.cpp
index 4028270..17150794 100644
--- a/third_party/WebKit/Source/platform/fonts/Font.cpp
+++ b/third_party/WebKit/Source/platform/fonts/Font.cpp
@@ -409,14 +409,10 @@
 
 CodePath Font::codePath(const TextRunPaintInfo& runInfo) const
 {
-// TODO(eae): Disable the always use complex text feature on Android for now as
-// it caused a memory regression for webview. crbug.com/577306
-#if !OS(ANDROID)
     if (RuntimeEnabledFeatures::alwaysUseComplexTextEnabled()
         || LayoutTestSupport::alwaysUseComplexTextForTest()) {
         return ComplexPath;
     }
-#endif
 
     const TextRun& run = runInfo.run;
 
diff --git a/third_party/WebKit/Source/platform/graphics/GraphicsContext.cpp b/third_party/WebKit/Source/platform/graphics/GraphicsContext.cpp
index 9536579..57f68b9 100644
--- a/third_party/WebKit/Source/platform/graphics/GraphicsContext.cpp
+++ b/third_party/WebKit/Source/platform/graphics/GraphicsContext.cpp
@@ -75,8 +75,8 @@
     m_paintState = m_paintStateStack.last().get();
 
     if (contextDisabled()) {
-        DEFINE_STATIC_LOCAL(RefPtr<SkCanvas>, nullCanvas, (adoptRef(SkCreateNullCanvas())));
-        m_canvas = nullCanvas.get();
+        DEFINE_STATIC_REF(SkCanvas, nullCanvas, (adoptRef(SkCreateNullCanvas())));
+        m_canvas = nullCanvas;
     }
 }
 
diff --git a/third_party/WebKit/Source/platform/graphics/compositing/PaintArtifactCompositor.cpp b/third_party/WebKit/Source/platform/graphics/compositing/PaintArtifactCompositor.cpp
index a78ac79..eac07130 100644
--- a/third_party/WebKit/Source/platform/graphics/compositing/PaintArtifactCompositor.cpp
+++ b/third_party/WebKit/Source/platform/graphics/compositing/PaintArtifactCompositor.cpp
@@ -95,6 +95,21 @@
     return list;
 }
 
+static gfx::Transform transformToRoot(const TransformPaintPropertyNode* currentSpace)
+{
+    TransformationMatrix matrix;
+    while (currentSpace) {
+        TransformationMatrix localMatrix = currentSpace->matrix();
+        localMatrix.applyTransformOrigin(currentSpace->origin());
+        matrix = localMatrix * matrix;
+        currentSpace = currentSpace->parent();
+    }
+
+    gfx::Transform transform;
+    transform.matrix() = TransformationMatrix::toSkMatrix44(matrix);
+    return transform;
+}
+
 void PaintArtifactCompositor::update(const PaintArtifact& paintArtifact)
 {
     ASSERT(m_rootLayer);
@@ -114,7 +129,7 @@
         scoped_refptr<cc::PictureLayer> layer = cc::PictureLayer::Create(cc::LayerSettings(), contentLayerClient.get());
         layer->SetPosition(gfx::PointF());
         layer->SetBounds(combinedBounds.size());
-        // TODO(jbroman): Layer transforms would be nice.
+        layer->SetTransform(transformToRoot(paintChunk.properties.transform.get()));
         layer->SetIsDrawable(true);
         layer->SetNeedsDisplay();
         m_contentLayerClients.append(contentLayerClient.release());
diff --git a/third_party/WebKit/Source/platform/graphics/paint/README.md b/third_party/WebKit/Source/platform/graphics/paint/README.md
index d886bcd..4b29640 100644
--- a/third_party/WebKit/Source/platform/graphics/paint/README.md
+++ b/third_party/WebKit/Source/platform/graphics/paint/README.md
@@ -154,7 +154,7 @@
 them in SPv2.
 ***
 
-## Display item list
+## Paint controller
 
 Callers use `GraphicsContext` (via its drawing methods, and its
 `paintController()` accessor) and scoped recorder classes, which emit items into
@@ -175,3 +175,16 @@
 *** aside
 TODO(jbroman): Explain invalidation.
 ***
+
+## Paint artifact compositor
+
+The [`PaintArtifactCompositor`](PaintArtifactCompositor.h) is responsible for
+consuming the `PaintArtifact` produced by the `PaintController`, and converting
+it into a form suitable for the compositor to consume.
+
+At present, `PaintArtifactCompositor` creates a cc layer tree, with one layer
+for each paint chunk. In the future, it is expected that we will use heuristics
+to combine paint chunks into a smaller number of layers.
+
+The owner of the `PaintArtifactCompositor` (e.g. `WebView`) can then attach its
+root layer to the overall layer hierarchy to be displayed to the user.
diff --git a/third_party/WebKit/Source/platform/testing/TestingPlatformSupport.cpp b/third_party/WebKit/Source/platform/testing/TestingPlatformSupport.cpp
index 928e88c..94c2e7c 100644
--- a/third_party/WebKit/Source/platform/testing/TestingPlatformSupport.cpp
+++ b/third_party/WebKit/Source/platform/testing/TestingPlatformSupport.cpp
@@ -89,12 +89,6 @@
     return !m_config.hasDiscardableMemorySupport ? 0 : new TestingDiscardableMemory(bytes);
 }
 
-const unsigned char* TestingPlatformSupport::getTraceCategoryEnabledFlag(const char* categoryName)
-{
-    static const unsigned char tracingIsDisabled = 0;
-    return &tracingIsDisabled;
-}
-
 WebString TestingPlatformSupport::defaultLocale()
 {
     return WebString::fromUTF8("en-US");
diff --git a/third_party/WebKit/Source/platform/testing/TestingPlatformSupport.h b/third_party/WebKit/Source/platform/testing/TestingPlatformSupport.h
index 027ed1d..fcaec86 100644
--- a/third_party/WebKit/Source/platform/testing/TestingPlatformSupport.h
+++ b/third_party/WebKit/Source/platform/testing/TestingPlatformSupport.h
@@ -114,7 +114,6 @@
 
     // Platform:
     WebDiscardableMemory* allocateAndLockDiscardableMemory(size_t bytes) override;
-    const unsigned char* getTraceCategoryEnabledFlag(const char* categoryName) override;
     WebString defaultLocale() override;
     WebCompositorSupport* compositorSupport() override;
     WebThread* currentThread() override;
diff --git a/third_party/WebKit/Source/web/PageOverlay.cpp b/third_party/WebKit/Source/web/PageOverlay.cpp
index d5b15440..0bcd39e 100644
--- a/third_party/WebKit/Source/web/PageOverlay.cpp
+++ b/third_party/WebKit/Source/web/PageOverlay.cpp
@@ -31,6 +31,7 @@
 #include "core/frame/FrameHost.h"
 #include "core/frame/Settings.h"
 #include "core/page/Page.h"
+#include "core/page/scrolling/ScrollingCoordinator.h"
 #include "platform/graphics/GraphicsContext.h"
 #include "platform/graphics/GraphicsLayer.h"
 #include "platform/graphics/GraphicsLayerClient.h"
@@ -84,7 +85,7 @@
 
         // This is required for contents of overlay to stay in sync with the page while scrolling.
         WebLayer* platformLayer = m_layer->platformLayer();
-        platformLayer->setShouldScrollOnMainThread(true);
+        platformLayer->addMainThreadScrollingReasons(WebMainThreadScrollingReason::PageOverlay);
         page->frameHost().visualViewport().containerLayer()->addChild(m_layer.get());
     }
 
diff --git a/third_party/WebKit/Source/web/ServiceWorkerGlobalScopeProxy.cpp b/third_party/WebKit/Source/web/ServiceWorkerGlobalScopeProxy.cpp
index dd12697..53cfd75 100644
--- a/third_party/WebKit/Source/web/ServiceWorkerGlobalScopeProxy.cpp
+++ b/third_party/WebKit/Source/web/ServiceWorkerGlobalScopeProxy.cpp
@@ -111,6 +111,7 @@
     FetchEventInit eventInit;
     eventInit.setCancelable(true);
     eventInit.setRequest(request);
+    eventInit.setClientId(webRequest.isMainResourceLoad() ? WebString() : webRequest.clientId());
     eventInit.setIsReload(webRequest.isReload());
     RefPtrWillBeRawPtr<FetchEvent> fetchEvent(FetchEvent::create(EventTypeNames::fetch, eventInit, observer));
     defaultPrevented = !workerGlobalScope()->dispatchEvent(fetchEvent.release());
diff --git a/third_party/WebKit/Source/web/WebInputEvent.cpp b/third_party/WebKit/Source/web/WebInputEvent.cpp
index 4f6054d5..782aef8 100644
--- a/third_party/WebKit/Source/web/WebInputEvent.cpp
+++ b/third_party/WebKit/Source/web/WebInputEvent.cpp
@@ -54,7 +54,7 @@
 };
 
 struct SameSizeAsWebGestureEvent : public SameSizeAsWebInputEvent {
-    int gestureData[11];
+    int gestureData[12];
 };
 
 struct SameSizeAsWebTouchEvent : public SameSizeAsWebInputEvent {
diff --git a/third_party/WebKit/Source/web/WebInputEventConversion.cpp b/third_party/WebKit/Source/web/WebInputEventConversion.cpp
index d10f2c14..95ac99cc 100644
--- a/third_party/WebKit/Source/web/WebInputEventConversion.cpp
+++ b/third_party/WebKit/Source/web/WebInputEventConversion.cpp
@@ -204,6 +204,19 @@
         m_data.m_scroll.m_velocityY = e.data.scrollUpdate.velocityY;
         m_data.m_scroll.m_preventPropagation = e.data.scrollUpdate.preventPropagation;
         m_data.m_scroll.m_inertial = e.data.scrollUpdate.inertial;
+        switch (e.data.scrollUpdate.deltaUnits) {
+        case WebGestureEvent::ScrollUnits::PrecisePixels:
+            m_data.m_scroll.m_deltaUnits = ScrollGranularity::ScrollByPrecisePixel;
+            break;
+        case WebGestureEvent::ScrollUnits::Pixels:
+            m_data.m_scroll.m_deltaUnits = ScrollGranularity::ScrollByPixel;
+            break;
+        case WebGestureEvent::ScrollUnits::Page:
+            m_data.m_scroll.m_deltaUnits = ScrollGranularity::ScrollByPage;
+            break;
+        default:
+            ASSERT_NOT_REACHED();
+        }
         break;
     case WebInputEvent::GestureTap:
         m_type = PlatformEvent::GestureTap;
diff --git a/third_party/WebKit/Source/web/WebViewImpl.cpp b/third_party/WebKit/Source/web/WebViewImpl.cpp
index 416f9d82..704d4cde 100644
--- a/third_party/WebKit/Source/web/WebViewImpl.cpp
+++ b/third_party/WebKit/Source/web/WebViewImpl.cpp
@@ -1981,7 +1981,7 @@
             PlatformGestureEvent endScrollEvent(PlatformEvent::GestureScrollEnd,
                 m_positionOnFlingStart, m_globalPositionOnFlingStart,
                 IntSize(), 0, PlatformEvent::NoModifiers, lastFlingSourceDevice == WebGestureDeviceTouchpad ? PlatformGestureSourceTouchpad : PlatformGestureSourceTouchscreen);
-            endScrollEvent.setScrollGestureData(0, 0, 0, 0, true, false, -1 /* null plugin id */);
+            endScrollEvent.setScrollGestureData(0, 0, ScrollByPrecisePixel, 0, 0, true, false, -1 /* null plugin id */);
 
             mainFrameImpl()->frame()->eventHandler().handleGestureScrollEnd(endScrollEvent);
         }
diff --git a/third_party/WebKit/Source/web/mac/WebSubstringUtil.mm b/third_party/WebKit/Source/web/mac/WebSubstringUtil.mm
index bd4c4a9..350e9cb 100644
--- a/third_party/WebKit/Source/web/mac/WebSubstringUtil.mm
+++ b/third_party/WebKit/Source/web/mac/WebSubstringUtil.mm
@@ -97,7 +97,7 @@
             [attrs removeObjectForKey:NSBackgroundColorAttributeName];
 
         Vector<UChar> characters;
-        it.appendTextTo(characters);
+        it.copyTextTo(characters);
         NSString* substring =
             [[[NSString alloc] initWithCharacters:characters.data()
                                            length:characters.size()] autorelease];
diff --git a/third_party/WebKit/Source/web/tests/VisualViewportTest.cpp b/third_party/WebKit/Source/web/tests/VisualViewportTest.cpp
index 26e906b..a64b808c 100644
--- a/third_party/WebKit/Source/web/tests/VisualViewportTest.cpp
+++ b/third_party/WebKit/Source/web/tests/VisualViewportTest.cpp
@@ -1474,7 +1474,7 @@
         IntPoint(0, 0),
         IntSize(5, 5),
         0, PlatformEvent::NoModifiers, PlatformGestureSourceTouchpad);
-    gsu.setScrollGestureData(-50, -60, 1, 1, false, false, -1 /* null plugin id */);
+    gsu.setScrollGestureData(-50, -60, ScrollByPrecisePixel, 1, 1, false, false, -1 /* null plugin id */);
 
     frame()->eventHandler().handleGestureEvent(gsu);
 
diff --git a/third_party/WebKit/Source/web/tests/WebInputEventConversionTest.cpp b/third_party/WebKit/Source/web/tests/WebInputEventConversionTest.cpp
index fc6688a..b7389642 100644
--- a/third_party/WebKit/Source/web/tests/WebInputEventConversionTest.cpp
+++ b/third_party/WebKit/Source/web/tests/WebInputEventConversionTest.cpp
@@ -441,7 +441,7 @@
     {
         PlatformGestureEvent platformGestureEvent(PlatformEvent::GestureScrollUpdate, IntPoint(10, 12), IntPoint(20, 22), IntSize(25, 27), 0,
             PlatformEvent::NoModifiers, PlatformGestureSourceTouchscreen);
-        platformGestureEvent.setScrollGestureData(30, 32, 40, 42, true, true, -1 /* null plugin id */);
+        platformGestureEvent.setScrollGestureData(30, 32, ScrollByPrecisePixel, 40, 42, true, true, -1 /* null plugin id */);
         // FIXME: GestureEvent does not preserve velocityX, velocityY,
         // or preventPropagation. It also fails to scale
         // coordinates (x, y, deltaX, deltaY) to the page scale. This
diff --git a/third_party/WebKit/Source/wtf/ArrayBufferBuilder.h b/third_party/WebKit/Source/wtf/ArrayBufferBuilder.h
index 38b285a0..c2b25859 100644
--- a/third_party/WebKit/Source/wtf/ArrayBufferBuilder.h
+++ b/third_party/WebKit/Source/wtf/ArrayBufferBuilder.h
@@ -31,6 +31,7 @@
 #ifndef ArrayBufferBuilder_h
 #define ArrayBufferBuilder_h
 
+#include "wtf/Allocator.h"
 #include "wtf/ArrayBuffer.h"
 #include "wtf/Noncopyable.h"
 #include "wtf/RefPtr.h"
@@ -40,10 +41,11 @@
 
 // A utility class to build an ArrayBuffer instance. Validity must be checked
 // by isValid() before using an instance.
-class WTF_EXPORT ArrayBufferBuilder {
+class WTF_EXPORT ArrayBufferBuilder final {
     // Disallow copying since it's expensive and we don't want code to do it by
     // accident.
     WTF_MAKE_NONCOPYABLE(ArrayBufferBuilder);
+    USING_FAST_MALLOC(ArrayBufferBuilder);
 
 public:
     // Creates an ArrayBufferBuilder using the default capacity.
diff --git a/third_party/WebKit/Source/wtf/ArrayBufferContents.h b/third_party/WebKit/Source/wtf/ArrayBufferContents.h
index 32cfbf4..3050379 100644
--- a/third_party/WebKit/Source/wtf/ArrayBufferContents.h
+++ b/third_party/WebKit/Source/wtf/ArrayBufferContents.h
@@ -27,6 +27,7 @@
 #ifndef ArrayBufferContents_h
 #define ArrayBufferContents_h
 
+#include "wtf/Allocator.h"
 #include "wtf/Assertions.h"
 #include "wtf/Noncopyable.h"
 #include "wtf/RefPtr.h"
@@ -38,6 +39,7 @@
 
 class WTF_EXPORT ArrayBufferContents {
     WTF_MAKE_NONCOPYABLE(ArrayBufferContents);
+    DISALLOW_NEW_EXCEPT_PLACEMENT_NEW();
 public:
     enum InitializationPolicy {
         ZeroInitialize,
diff --git a/third_party/WebKit/Source/wtf/ArrayPiece.h b/third_party/WebKit/Source/wtf/ArrayPiece.h
index 7c7c7f1..fcad5d2 100644
--- a/third_party/WebKit/Source/wtf/ArrayPiece.h
+++ b/third_party/WebKit/Source/wtf/ArrayPiece.h
@@ -5,6 +5,7 @@
 #ifndef ArrayPiece_h
 #define ArrayPiece_h
 
+#include "wtf/Allocator.h"
 #include "wtf/Forward.h"
 #include "wtf/WTFExport.h"
 
@@ -20,6 +21,7 @@
 // IMPORTANT: The data contained by ArrayPiece is NOT OWNED, so caution must be
 //            taken to ensure it is kept alive.
 class WTF_EXPORT ArrayPiece {
+    DISALLOW_NEW();
 public:
     // Constructs a "null" ArrayPiece object.
     ArrayPiece();
diff --git a/third_party/WebKit/Source/wtf/BitArray.h b/third_party/WebKit/Source/wtf/BitArray.h
index 2a39c71f..76258b33 100644
--- a/third_party/WebKit/Source/wtf/BitArray.h
+++ b/third_party/WebKit/Source/wtf/BitArray.h
@@ -26,6 +26,7 @@
 #ifndef BitArray_h
 #define BitArray_h
 
+#include "wtf/Allocator.h"
 #include "wtf/Assertions.h"
 #include <string.h>
 
@@ -33,6 +34,7 @@
 
 template<unsigned arraySize>
 class BitArray {
+    USING_FAST_MALLOC(BitArray);
 public:
     BitArray(bool value = false)
     {
diff --git a/third_party/WebKit/Source/wtf/BitVector.h b/third_party/WebKit/Source/wtf/BitVector.h
index e540725c..b4d8dea 100644
--- a/third_party/WebKit/Source/wtf/BitVector.h
+++ b/third_party/WebKit/Source/wtf/BitVector.h
@@ -26,6 +26,7 @@
 #ifndef BitVector_h
 #define BitVector_h
 
+#include "wtf/Allocator.h"
 #include "wtf/Assertions.h"
 #include "wtf/StdLibExtras.h"
 #include "wtf/WTFExport.h"
@@ -56,6 +57,7 @@
 // space.
 
 class WTF_EXPORT BitVector {
+    DISALLOW_NEW();
 public:
     BitVector()
         : m_bitsOrPointer(makeInlineBits(0))
@@ -195,6 +197,7 @@
     }
 
     class WTF_EXPORT OutOfLineBits {
+        DISALLOW_NEW_EXCEPT_PLACEMENT_NEW();
     public:
         size_t numBits() const { return m_numBits; }
         size_t numWords() const { return (m_numBits + bitsInPointer() - 1) / bitsInPointer(); }
diff --git a/third_party/WebKit/Source/wtf/BloomFilter.h b/third_party/WebKit/Source/wtf/BloomFilter.h
index a3a36521..1704a827 100644
--- a/third_party/WebKit/Source/wtf/BloomFilter.h
+++ b/third_party/WebKit/Source/wtf/BloomFilter.h
@@ -26,6 +26,7 @@
 #ifndef BloomFilter_h
 #define BloomFilter_h
 
+#include "wtf/Allocator.h"
 #include "wtf/Compiler.h"
 #include "wtf/text/AtomicString.h"
 
@@ -36,6 +37,7 @@
 // keys and m is the table size (==2^keyBits).
 template <unsigned keyBits>
 class BloomFilter {
+    USING_FAST_MALLOC(BloomFilter);
 public:
     static_assert(keyBits <= 16, "bloom filter key size check");
 
diff --git a/third_party/WebKit/Source/wtf/Deque.h b/third_party/WebKit/Source/wtf/Deque.h
index 23323c0..cd7bc0c8 100644
--- a/third_party/WebKit/Source/wtf/Deque.h
+++ b/third_party/WebKit/Source/wtf/Deque.h
@@ -131,6 +131,7 @@
 
 template <typename T, size_t inlineCapacity, typename Allocator>
 class DequeIteratorBase {
+    DISALLOW_NEW();
 protected:
     DequeIteratorBase();
     DequeIteratorBase(const Deque<T, inlineCapacity, Allocator>*, size_t);
diff --git a/third_party/WebKit/Source/wtf/DoublyLinkedList.h b/third_party/WebKit/Source/wtf/DoublyLinkedList.h
index 1c82226..4440234 100644
--- a/third_party/WebKit/Source/wtf/DoublyLinkedList.h
+++ b/third_party/WebKit/Source/wtf/DoublyLinkedList.h
@@ -26,6 +26,8 @@
 #ifndef DoublyLinkedList_h
 #define DoublyLinkedList_h
 
+#include "wtf/Allocator.h"
+
 namespace WTF {
 
 // This class allows nodes to share code without dictating data member layout.
@@ -67,6 +69,7 @@
 }
 
 template<typename T> class DoublyLinkedList {
+    USING_FAST_MALLOC(DoublyLinkedList);
 public:
     DoublyLinkedList();
 
diff --git a/third_party/WebKit/Source/wtf/Functional.h b/third_party/WebKit/Source/wtf/Functional.h
index 6035e827..16644a1 100644
--- a/third_party/WebKit/Source/wtf/Functional.h
+++ b/third_party/WebKit/Source/wtf/Functional.h
@@ -26,6 +26,7 @@
 #ifndef WTF_Functional_h
 #define WTF_Functional_h
 
+#include "wtf/Allocator.h"
 #include "wtf/Assertions.h"
 #include "wtf/PassOwnPtr.h"
 #include "wtf/PassRefPtr.h"
@@ -49,6 +50,7 @@
 // Bound static functions:
 template<typename R, typename... Params>
 class FunctionWrapper<R(*)(Params...)> {
+    DISALLOW_NEW();
 public:
     typedef R ResultType;
 
@@ -70,6 +72,7 @@
 
 template<typename R, typename C, typename... Params>
 class FunctionWrapper<R(C::*)(Params...)> {
+    DISALLOW_NEW();
 public:
     typedef R ResultType;
 
@@ -135,6 +138,7 @@
 
 template<typename R, typename... Args>
 class Function<R(Args...)> {
+    USING_FAST_MALLOC(Function);
     WTF_MAKE_NONCOPYABLE(Function);
 public:
     virtual ~Function() { }
diff --git a/third_party/WebKit/Source/wtf/HashCountedSet.h b/third_party/WebKit/Source/wtf/HashCountedSet.h
index 97340589..58b55f0 100644
--- a/third_party/WebKit/Source/wtf/HashCountedSet.h
+++ b/third_party/WebKit/Source/wtf/HashCountedSet.h
@@ -37,6 +37,7 @@
     typename Allocator = PartitionAllocator>
 class HashCountedSet {
     WTF_USE_ALLOCATOR(HashCountedSet, Allocator);
+    WTF_MAKE_NONCOPYABLE(HashCountedSet);
 private:
     typedef HashMap<Value, unsigned, HashFunctions, Traits, HashTraits<unsigned>, Allocator> ImplType;
 public:
diff --git a/third_party/WebKit/Source/wtf/HashIterators.h b/third_party/WebKit/Source/wtf/HashIterators.h
index e751e9d..2133e84 100644
--- a/third_party/WebKit/Source/wtf/HashIterators.h
+++ b/third_party/WebKit/Source/wtf/HashIterators.h
@@ -26,6 +26,8 @@
 #ifndef WTF_HashIterators_h
 #define WTF_HashIterators_h
 
+#include "wtf/Allocator.h"
+
 namespace WTF {
 
 template <typename HashTableType, typename KeyType, typename MappedType> struct HashTableConstKeysIterator;
@@ -35,6 +37,7 @@
 
 template <typename HashTableType, typename KeyType, typename MappedType>
 struct HashTableConstIteratorAdapter<HashTableType, KeyValuePair<KeyType, MappedType>> {
+    STACK_ALLOCATED();
 private:
     typedef KeyValuePair<KeyType, MappedType> ValueType;
 public:
@@ -59,6 +62,7 @@
 
 template <typename HashTableType, typename KeyType, typename MappedType>
 struct HashTableIteratorAdapter<HashTableType, KeyValuePair<KeyType, MappedType>> {
+    STACK_ALLOCATED();
 private:
     typedef KeyValuePair<KeyType, MappedType> ValueType;
 public:
@@ -89,6 +93,7 @@
 
 template <typename HashTableType, typename KeyType, typename MappedType>
 struct HashTableConstKeysIterator {
+    STACK_ALLOCATED();
 private:
     typedef HashTableConstIteratorAdapter<HashTableType, KeyValuePair<KeyType, MappedType>> ConstIterator;
 
@@ -107,6 +112,7 @@
 
 template <typename HashTableType, typename KeyType, typename MappedType>
 struct HashTableConstValuesIterator {
+    STACK_ALLOCATED();
 private:
     typedef HashTableConstIteratorAdapter<HashTableType, KeyValuePair<KeyType, MappedType>> ConstIterator;
 
@@ -125,6 +131,7 @@
 
 template <typename HashTableType, typename KeyType, typename MappedType>
 struct HashTableKeysIterator {
+    STACK_ALLOCATED();
 private:
     typedef HashTableIteratorAdapter<HashTableType, KeyValuePair<KeyType, MappedType>> Iterator;
     typedef HashTableConstIteratorAdapter<HashTableType, KeyValuePair<KeyType, MappedType>> ConstIterator;
@@ -150,6 +157,7 @@
 
 template <typename HashTableType, typename KeyType, typename MappedType>
 struct HashTableValuesIterator {
+    STACK_ALLOCATED();
 private:
     typedef HashTableIteratorAdapter<HashTableType, KeyValuePair<KeyType, MappedType>> Iterator;
     typedef HashTableConstIteratorAdapter<HashTableType, KeyValuePair<KeyType, MappedType>> ConstIterator;
diff --git a/third_party/WebKit/Source/wtf/HashMap.h b/third_party/WebKit/Source/wtf/HashMap.h
index 8cb46d4..71c395a 100644
--- a/third_party/WebKit/Source/wtf/HashMap.h
+++ b/third_party/WebKit/Source/wtf/HashMap.h
@@ -29,13 +29,16 @@
 template <typename KeyTraits, typename MappedTraits> struct HashMapValueTraits;
 
 template <typename T> struct ReferenceTypeMaker {
+    STATIC_ONLY(ReferenceTypeMaker);
     typedef T& ReferenceType;
 };
 template <typename T> struct ReferenceTypeMaker<T&> {
+    STATIC_ONLY(ReferenceTypeMaker);
     typedef T& ReferenceType;
 };
 
 struct KeyValuePairKeyExtractor {
+    STATIC_ONLY(KeyValuePairKeyExtractor);
     template <typename T>
     static const typename T::KeyType& extract(const T& p) { return p.key; }
 };
@@ -171,6 +174,7 @@
 template <typename KeyArg, typename MappedArg, typename HashArg, typename KeyTraitsArg, typename MappedTraitsArg, typename Allocator>
 class HashMap<KeyArg, MappedArg, HashArg, KeyTraitsArg, MappedTraitsArg, Allocator>::HashMapKeysProxy :
     private HashMap<KeyArg, MappedArg, HashArg, KeyTraitsArg, MappedTraitsArg, Allocator> {
+    DISALLOW_NEW();
 public:
     typedef HashMap<KeyArg, MappedArg, HashArg, KeyTraitsArg, MappedTraitsArg, Allocator> HashMapType;
     typedef typename HashMapType::iterator::Keys iterator;
@@ -209,6 +213,7 @@
 template <typename KeyArg, typename MappedArg, typename HashArg,  typename KeyTraitsArg, typename MappedTraitsArg, typename Allocator>
 class HashMap<KeyArg, MappedArg, HashArg, KeyTraitsArg, MappedTraitsArg, Allocator>::HashMapValuesProxy :
     private HashMap<KeyArg, MappedArg, HashArg, KeyTraitsArg, MappedTraitsArg, Allocator> {
+    DISALLOW_NEW();
 public:
     typedef HashMap<KeyArg, MappedArg, HashArg, KeyTraitsArg, MappedTraitsArg, Allocator> HashMapType;
     typedef typename HashMapType::iterator::Values iterator;
@@ -246,6 +251,7 @@
 
 template <typename KeyTraits, typename MappedTraits>
 struct HashMapValueTraits : KeyValuePairHashTraits<KeyTraits, MappedTraits> {
+    STATIC_ONLY(HashMapValueTraits);
     static const bool hasIsEmptyValueFunction = true;
     static bool isEmptyValue(const typename KeyValuePairHashTraits<KeyTraits, MappedTraits>::TraitType& value)
     {
@@ -255,6 +261,7 @@
 
 template <typename ValueTraits, typename HashFunctions>
 struct HashMapTranslator {
+    STATIC_ONLY(HashMapTranslator);
     template <typename T> static unsigned hash(const T& key) { return HashFunctions::hash(key); }
     template <typename T, typename U> static bool equal(const T& a, const U& b) { return HashFunctions::equal(a, b); }
     template <typename T, typename U, typename V> static void translate(T& location, const U& key, const V& mapped)
@@ -266,6 +273,7 @@
 
 template <typename ValueTraits, typename Translator>
 struct HashMapTranslatorAdapter {
+    STATIC_ONLY(HashMapTranslatorAdapter);
     template <typename T> static unsigned hash(const T& key) { return Translator::hash(key); }
     template <typename T, typename U> static bool equal(const T& a, const U& b) { return Translator::equal(a, b); }
     template <typename T, typename U, typename V> static void translate(T& location, const U& key, const V& mapped, unsigned hashCode)
@@ -505,6 +513,7 @@
 #if !ENABLE(OILPAN)
 template <typename T, typename U, typename V, typename W, typename X>
 struct NeedsTracing<HashMap<T, U, V, W, X>> {
+    STATIC_ONLY(NeedsTracing);
     static const bool value = false;
 };
 #endif
diff --git a/third_party/WebKit/Source/wtf/HashSet.h b/third_party/WebKit/Source/wtf/HashSet.h
index cf37e1ac..08e5902 100644
--- a/third_party/WebKit/Source/wtf/HashSet.h
+++ b/third_party/WebKit/Source/wtf/HashSet.h
@@ -124,12 +124,14 @@
 };
 
 struct IdentityExtractor {
+    STATIC_ONLY(IdentityExtractor);
     template <typename T>
     static const T& extract(const T& t) { return t; }
 };
 
 template <typename Translator>
 struct HashSetTranslatorAdapter {
+    STATIC_ONLY(HashSetTranslatorAdapter);
     template <typename T> static unsigned hash(const T& key) { return Translator::hash(key); }
     template <typename T, typename U> static bool equal(const T& a, const U& b) { return Translator::equal(a, b); }
     template <typename T, typename U> static void translate(T& location, const U& key, const U&, unsigned hashCode)
diff --git a/third_party/WebKit/Source/wtf/HashTable.h b/third_party/WebKit/Source/wtf/HashTable.h
index 960ce296..85b68a72 100644
--- a/third_party/WebKit/Source/wtf/HashTable.h
+++ b/third_party/WebKit/Source/wtf/HashTable.h
@@ -21,6 +21,7 @@
 #define WTF_HashTable_h
 
 #include "wtf/Alignment.h"
+#include "wtf/Allocator.h"
 #include "wtf/Assertions.h"
 #include "wtf/ConditionalDestructor.h"
 #include "wtf/HashTraits.h"
@@ -72,6 +73,7 @@
 #if DUMP_HASHTABLE_STATS
 
 struct HashTableStats {
+    STATIC_ONLY(HashTableStats);
     // The following variables are all atomically incremented when modified.
     static int numAccesses;
     static int numRehashes;
@@ -104,7 +106,8 @@
 typedef enum { HashItemKnownGood } HashItemKnownGoodTag;
 
 template <typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits, typename Allocator>
-class HashTableConstIterator {
+class HashTableConstIterator final {
+    DISALLOW_NEW();
 private:
     typedef HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits, Allocator> HashTableType;
     typedef HashTableIterator<Key, Value, Extractor, HashFunctions, Traits, KeyTraits, Allocator> iterator;
@@ -204,7 +207,8 @@
 };
 
 template <typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits, typename Allocator>
-class HashTableIterator {
+class HashTableIterator final {
+    DISALLOW_NEW();
 private:
     typedef HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits, Allocator> HashTableType;
     typedef HashTableIterator<Key, Value, Extractor, HashFunctions, Traits, KeyTraits, Allocator> iterator;
@@ -260,6 +264,7 @@
 template <typename T, typename Allocator, bool useSwap = !IsTriviallyDestructible<T>::value>
 struct Mover;
 template <typename T, typename Allocator> struct Mover<T, Allocator, true> {
+    STATIC_ONLY(Mover);
     static void move(T& from, T& to)
     {
         // The key and value cannot be swapped atomically, and it would be wrong
@@ -273,17 +278,20 @@
 };
 
 template <typename T, typename Allocator> struct Mover<T, Allocator, false> {
+    STATIC_ONLY(Mover);
     static void move(T& from, T& to) { to = from; }
 };
 
 template <typename HashFunctions> class IdentityHashTranslator {
+    STATIC_ONLY(IdentityHashTranslator);
 public:
     template <typename T> static unsigned hash(const T& key) { return HashFunctions::hash(key); }
     template <typename T, typename U> static bool equal(const T& a, const U& b) { return HashFunctions::equal(a, b); }
     template <typename T, typename U, typename V> static void translate(T& location, const U&, const V& value) { location = value; }
 };
 
-template <typename HashTableType, typename ValueType> struct HashTableAddResult {
+template <typename HashTableType, typename ValueType> struct HashTableAddResult final {
+    STACK_ALLOCATED();
     HashTableAddResult(const HashTableType* container, ValueType* storedValue, bool isNewEntry)
         : storedValue(storedValue)
         , isNewEntry(isNewEntry)
@@ -319,6 +327,7 @@
 
 template <typename Value, typename Extractor, typename KeyTraits>
 struct HashTableHelper {
+    STATIC_ONLY(HashTableHelper);
     static bool isEmptyBucket(const Value& value) { return isHashTraitsEmptyValue<KeyTraits>(Extractor::extract(value)); }
     static bool isDeletedBucket(const Value& value) { return KeyTraits::isDeletedValue(Extractor::extract(value)); }
     static bool isEmptyOrDeletedBucket(const Value& value) { return isEmptyBucket(value) || isDeletedBucket(value); }
@@ -326,6 +335,7 @@
 
 template <typename HashTranslator, typename KeyTraits, bool safeToCompareToEmptyOrDeleted>
 struct HashTableKeyChecker {
+    STATIC_ONLY(HashTableKeyChecker);
     // There's no simple generic way to make this check if
     // safeToCompareToEmptyOrDeleted is false, so the check always passes.
     template <typename T>
@@ -334,6 +344,7 @@
 
 template <typename HashTranslator, typename KeyTraits>
 struct HashTableKeyChecker<HashTranslator, KeyTraits, true> {
+    STATIC_ONLY(HashTableKeyChecker);
     template <typename T>
     static bool checkKey(const T& key)
     {
@@ -346,7 +357,8 @@
 // undefined behavior.  For pointer keys this means that null pointers are not
 // allowed unless you supply custom key traits.
 template <typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits, typename Allocator>
-class HashTable : public ConditionalDestructor<HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits, Allocator>, Allocator::isGarbageCollected> {
+class HashTable final : public ConditionalDestructor<HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits, Allocator>, Allocator::isGarbageCollected> {
+    DISALLOW_NEW();
 public:
     typedef HashTableIterator<Key, Value, Extractor, HashFunctions, Traits, KeyTraits, Allocator> iterator;
     typedef HashTableConstIterator<Key, Value, Extractor, HashFunctions, Traits, KeyTraits, Allocator> const_iterator;
@@ -363,6 +375,7 @@
 
 #if DUMP_HASHTABLE_STATS_PER_TABLE
     struct Stats {
+        DISALLOW_NEW(Stats);
         Stats()
             : numAccesses(0)
             , numRehashes(0)
@@ -768,6 +781,7 @@
 template <bool emptyValueIsZero> struct HashTableBucketInitializer;
 
 template <> struct HashTableBucketInitializer<false> {
+    STATIC_ONLY(HashTableBucketInitializer);
     template <typename Traits, typename Value> static void initialize(Value& bucket)
     {
         new (NotNull, &bucket) Value(Traits::emptyValue());
@@ -775,6 +789,7 @@
 };
 
 template <> struct HashTableBucketInitializer<true> {
+    STATIC_ONLY(HashTableBucketInitializer);
     template <typename Traits, typename Value> static void initialize(Value& bucket)
     {
         // This initializes the bucket without copying the empty value.  That
@@ -1265,6 +1280,7 @@
 
 template <typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits, typename Allocator>
 struct WeakProcessingHashTableHelper<NoWeakHandlingInCollections, Key, Value, Extractor, HashFunctions, Traits, KeyTraits, Allocator> {
+    STATIC_ONLY(WeakProcessingHashTableHelper);
     static void process(typename Allocator::Visitor* visitor, void* closure) {}
     static void ephemeronIteration(typename Allocator::Visitor* visitor, void* closure) {}
     static void ephemeronIterationDone(typename Allocator::Visitor* visitor, void* closure) {}
@@ -1272,6 +1288,7 @@
 
 template <typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits, typename Allocator>
 struct WeakProcessingHashTableHelper<WeakHandlingInCollections, Key, Value, Extractor, HashFunctions, Traits, KeyTraits, Allocator> {
+    STATIC_ONLY(WeakProcessingHashTableHelper);
     // Used for purely weak and for weak-and-strong tables (ephemerons).
     static void process(typename Allocator::Visitor* visitor, void* closure)
     {
@@ -1393,6 +1410,7 @@
 // iterator adapters
 
 template <typename HashTableType, typename Traits> struct HashTableConstIteratorAdapter {
+    STACK_ALLOCATED();
     HashTableConstIteratorAdapter() {}
     HashTableConstIteratorAdapter(const typename HashTableType::const_iterator& impl) : m_impl(impl) {}
     typedef typename Traits::IteratorConstGetType GetType;
@@ -1409,6 +1427,7 @@
 };
 
 template <typename HashTableType, typename Traits> struct HashTableIteratorAdapter {
+    STACK_ALLOCATED();
     typedef typename Traits::IteratorGetType GetType;
     typedef typename HashTableType::ValueTraits::IteratorGetType SourceGetType;
 
diff --git a/third_party/WebKit/Source/wtf/LinkedHashSet.h b/third_party/WebKit/Source/wtf/LinkedHashSet.h
index 58d97fb..9e20239 100644
--- a/third_party/WebKit/Source/wtf/LinkedHashSet.h
+++ b/third_party/WebKit/Source/wtf/LinkedHashSet.h
@@ -51,6 +51,7 @@
 template<typename Value, typename ValueTraits, typename Allocator> struct LinkedHashSetTraits;
 
 class LinkedHashSetNodeBase {
+    DISALLOW_NEW();
 public:
     LinkedHashSetNodeBase() : m_prev(this), m_next(this) { }
 
@@ -120,6 +121,7 @@
 
 template<typename ValueArg, typename Allocator>
 class LinkedHashSetNode : public LinkedHashSetNodeBase {
+    DISALLOW_NEW();
 public:
     LinkedHashSetNode(const ValueArg& value, LinkedHashSetNodeBase* prev, LinkedHashSetNodeBase* next)
         : LinkedHashSetNodeBase(prev, next)
@@ -163,7 +165,8 @@
     typedef LinkedHashSetConstReverseIterator<LinkedHashSet> const_reverse_iterator;
     friend class LinkedHashSetConstReverseIterator<LinkedHashSet>;
 
-    struct AddResult {
+    struct AddResult final {
+        STACK_ALLOCATED();
         AddResult(const typename ImplType::AddResult& hashTableAddResult)
             : storedValue(&hashTableAddResult.storedValue->m_value)
             , isNewEntry(hashTableAddResult.isNewEntry)
@@ -273,6 +276,7 @@
 
 template<typename Value, typename HashFunctions, typename Allocator>
 struct LinkedHashSetTranslator {
+    STATIC_ONLY(LinkedHashSetTranslator);
     typedef LinkedHashSetNode<Value, Allocator> Node;
     typedef LinkedHashSetNodeBase NodeBase;
     typedef typename HashTraits<Value>::PeekInType ValuePeekInType;
@@ -295,11 +299,13 @@
 
 template<typename Value, typename Allocator>
 struct LinkedHashSetExtractor {
+    STATIC_ONLY(LinkedHashSetExtractor);
     static const Value& extract(const LinkedHashSetNode<Value, Allocator>& node) { return node.m_value; }
 };
 
 template<typename Value, typename ValueTraitsArg, typename Allocator>
 struct LinkedHashSetTraits : public SimpleClassHashTraits<LinkedHashSetNode<Value, Allocator>> {
+    STATIC_ONLY(LinkedHashSetTraits);
     typedef LinkedHashSetNode<Value, Allocator> Node;
     typedef ValueTraitsArg ValueTraits;
 
@@ -319,6 +325,7 @@
     // the type inside the node.
     template<typename U = void>
     struct NeedsTracingLazily {
+        STATIC_ONLY(NeedsTracingLazily);
         static const bool value = ValueTraits::template NeedsTracingLazily<>::value;
     };
     static const WeakHandlingFlag weakHandlingFlag = ValueTraits::weakHandlingFlag;
@@ -326,6 +333,7 @@
 
 template<typename LinkedHashSetType>
 class LinkedHashSetIterator {
+    DISALLOW_NEW();
 private:
     typedef typename LinkedHashSetType::Node Node;
     typedef typename LinkedHashSetType::Traits Traits;
@@ -368,6 +376,7 @@
 
 template<typename LinkedHashSetType>
 class LinkedHashSetConstIterator {
+    DISALLOW_NEW();
 private:
     typedef typename LinkedHashSetType::Node Node;
     typedef typename LinkedHashSetType::Traits Traits;
@@ -571,6 +580,7 @@
 
 template<typename Translator>
 struct LinkedHashSetTranslatorAdapter {
+    STATIC_ONLY(LinkedHashSetTranslatorAdapter);
     template<typename T> static unsigned hash(const T& key) { return Translator::hash(key); }
     template<typename T, typename U> static bool equal(const T& a, const U& b) { return Translator::equal(a.m_value, b); }
 };
@@ -723,6 +733,7 @@
 #if !ENABLE(OILPAN)
 template<typename T, typename U, typename V>
 struct NeedsTracing<LinkedHashSet<T, U, V>> {
+    STATIC_ONLY(NeedsTracing);
     static const bool value = false;
 };
 #endif
diff --git a/third_party/WebKit/Source/wtf/LinkedStack.h b/third_party/WebKit/Source/wtf/LinkedStack.h
index b63cd06..07ef63c 100644
--- a/third_party/WebKit/Source/wtf/LinkedStack.h
+++ b/third_party/WebKit/Source/wtf/LinkedStack.h
@@ -58,9 +58,7 @@
 
     size_t size();
 
-    // This inner class used to be private but is now public on account of a
-    // possible MSVC bug. It can be made private again if we get rid of
-    // USING_FAST_MALLOC ever.
+private:
     class Node {
         USING_FAST_MALLOC(LinkedStack::Node);
     public:
@@ -69,8 +67,10 @@
         T m_data;
         OwnPtr<Node> m_next;
     };
+#if COMPILER(MSVC)
+    friend struct ::WTF::OwnedPtrDeleter<Node>;
+#endif
 
-private:
     OwnPtr<Node> m_head;
     size_t m_size;
 };
diff --git a/third_party/WebKit/Source/wtf/ListHashSet.h b/third_party/WebKit/Source/wtf/ListHashSet.h
index 0c0f26ef..d8710729 100644
--- a/third_party/WebKit/Source/wtf/ListHashSet.h
+++ b/third_party/WebKit/Source/wtf/ListHashSet.h
@@ -87,7 +87,8 @@
     friend class ListHashSetReverseIterator<ListHashSet>;
     friend class ListHashSetConstReverseIterator<ListHashSet>;
 
-    template <typename ValueType> struct HashTableAddResult {
+    template <typename ValueType> struct HashTableAddResult final {
+        STACK_ALLOCATED();
         HashTableAddResult(Node* storedValue, bool isNewEntry) : storedValue(storedValue), isNewEntry(isNewEntry) { }
         Node* storedValue;
         bool isNewEntry;
@@ -193,6 +194,7 @@
 // compiler otherwise gets into circular template dependencies when trying to do
 // sizeof on a node.
 template <typename ValueArg> class ListHashSetNodeBase {
+    DISALLOW_NEW();
 protected:
     ListHashSetNodeBase(const ValueArg& value)
         : m_value(value)
@@ -232,6 +234,7 @@
     typedef ListHashSetNodeBase<ValueArg> NodeBase;
 
     class AllocatorProvider {
+        DISALLOW_NEW();
     public:
         AllocatorProvider() : m_allocator(nullptr) {}
         void createAllocatorIfNeeded()
@@ -425,12 +428,14 @@
 };
 
 template <typename HashArg> struct ListHashSetNodeHashFunctions {
+    STATIC_ONLY(ListHashSetNodeHashFunctions);
     template <typename T> static unsigned hash(const T& key) { return HashArg::hash(key->m_value); }
     template <typename T> static bool equal(const T& a, const T& b) { return HashArg::equal(a->m_value, b->m_value); }
     static const bool safeToCompareToEmptyOrDeleted = false;
 };
 
 template <typename Set> class ListHashSetIterator {
+    DISALLOW_NEW();
 private:
     typedef typename Set::const_iterator const_iterator;
     typedef typename Set::Node Node;
@@ -471,6 +476,7 @@
 
 template <typename Set>
 class ListHashSetConstIterator {
+    DISALLOW_NEW();
 private:
     typedef typename Set::const_iterator const_iterator;
     typedef typename Set::Node Node;
@@ -539,6 +545,7 @@
 
 template <typename Set>
 class ListHashSetReverseIterator {
+    DISALLOW_NEW();
 private:
     typedef typename Set::const_reverse_iterator const_reverse_iterator;
     typedef typename Set::Node Node;
@@ -578,6 +585,7 @@
 };
 
 template <typename Set> class ListHashSetConstReverseIterator {
+    DISALLOW_NEW();
 private:
     typedef typename Set::reverse_iterator reverse_iterator;
     typedef typename Set::Node Node;
@@ -646,6 +654,7 @@
 
 template <typename HashFunctions>
 struct ListHashSetTranslator {
+    STATIC_ONLY(ListHashSetTranslator);
     template <typename T> static unsigned hash(const T& key) { return HashFunctions::hash(key); }
     template <typename T, typename U> static bool equal(const T& a, const U& b) { return HashFunctions::equal(a->m_value, b); }
     template <typename T, typename U, typename V> static void translate(T*& location, const U& key, const V& allocator)
@@ -760,6 +769,7 @@
 
 template <typename Translator>
 struct ListHashSetTranslatorAdapter {
+    STATIC_ONLY(ListHashSetTranslatorAdapter);
     template <typename T> static unsigned hash(const T& key) { return Translator::hash(key); }
     template <typename T, typename U> static bool equal(const T& a, const U& b) { return Translator::equal(a->m_value, b); }
 };
diff --git a/third_party/WebKit/Source/wtf/Locker.h b/third_party/WebKit/Source/wtf/Locker.h
index 39b435da..a1f3aba4 100644
--- a/third_party/WebKit/Source/wtf/Locker.h
+++ b/third_party/WebKit/Source/wtf/Locker.h
@@ -28,11 +28,13 @@
 #ifndef Locker_h
 #define Locker_h
 
+#include "wtf/Allocator.h"
 #include "wtf/Noncopyable.h"
 
 namespace WTF {
 
-template <typename T> class Locker {
+template <typename T> class Locker final {
+    STACK_ALLOCATED();
     WTF_MAKE_NONCOPYABLE(Locker);
 public:
     Locker(T& lockable) : m_lockable(lockable) { m_lockable.lock(); }
diff --git a/third_party/WebKit/Source/wtf/MathExtras.h b/third_party/WebKit/Source/wtf/MathExtras.h
index 34c2e04..2367947 100644
--- a/third_party/WebKit/Source/wtf/MathExtras.h
+++ b/third_party/WebKit/Source/wtf/MathExtras.h
@@ -26,6 +26,7 @@
 #ifndef WTF_MathExtras_h
 #define WTF_MathExtras_h
 
+#include "wtf/Allocator.h"
 #include "wtf/Assertions.h"
 #include "wtf/CPU.h"
 #include <cmath>
@@ -164,6 +165,7 @@
 // about unsafe code (even though we wouldn't actually be executing that code).
 template<bool canUseDirectComparison, typename LimitType, typename ValueType> class ClampToNonLongLongHelper;
 template<typename LimitType, typename ValueType> class ClampToNonLongLongHelper<true, LimitType, ValueType> {
+    STATIC_ONLY(ClampToNonLongLongHelper);
 public:
     static inline LimitType clampTo(ValueType value, LimitType min, LimitType max)
     {
@@ -172,6 +174,7 @@
 };
 
 template<typename LimitType, typename ValueType> class ClampToNonLongLongHelper<false, LimitType, ValueType> {
+    STATIC_ONLY(ClampToNonLongLongHelper);
 public:
     static inline LimitType clampTo(ValueType value, LimitType min, LimitType max)
     {
@@ -217,6 +220,7 @@
 // outside the representable range of the limit type, so we also have to check
 // for that case explicitly.
 template<typename ValueType> class ClampToHelper<long long int, ValueType> {
+    STATIC_ONLY(ClampToHelper);
 public:
     static inline long long int clampTo(ValueType value, long long int min, long long int max)
     {
@@ -238,6 +242,7 @@
 // This specialization handles the case where the above partial specialization
 // would be potentially incorrect.
 template<> class ClampToHelper<long long int, unsigned long long int> {
+    STATIC_ONLY(ClampToHelper);
 public:
     static inline long long int clampTo(unsigned long long int value, long long int min, long long int max)
     {
@@ -252,6 +257,7 @@
 // but because the lower-bound check is done for integer value types as well, we
 // don't need a <unsigned long long int, long long int> full specialization.
 template<typename ValueType> class ClampToHelper<unsigned long long int, ValueType> {
+    STATIC_ONLY(ClampToHelper);
 public:
     static inline unsigned long long int clampTo(ValueType value, unsigned long long int min, unsigned long long int max)
     {
diff --git a/third_party/WebKit/Source/wtf/Optional.h b/third_party/WebKit/Source/wtf/Optional.h
index c4f931e..1c2e422f 100644
--- a/third_party/WebKit/Source/wtf/Optional.h
+++ b/third_party/WebKit/Source/wtf/Optional.h
@@ -6,6 +6,7 @@
 #define Optional_h
 
 #include "wtf/Alignment.h"
+#include "wtf/Allocator.h"
 #include "wtf/Assertions.h"
 #include "wtf/Noncopyable.h"
 #include "wtf/StdLibExtras.h"
@@ -31,7 +32,8 @@
 // optional yields a const reference.
 
 template <typename T>
-class Optional {
+class Optional final {
+    DISALLOW_NEW();
     WTF_MAKE_NONCOPYABLE(Optional);
 public:
     Optional() : m_ptr(nullptr) { }
diff --git a/third_party/WebKit/Source/wtf/OwnPtr.h b/third_party/WebKit/Source/wtf/OwnPtr.h
index ec09c10e..0b0b58e 100644
--- a/third_party/WebKit/Source/wtf/OwnPtr.h
+++ b/third_party/WebKit/Source/wtf/OwnPtr.h
@@ -22,6 +22,7 @@
 #ifndef WTF_OwnPtr_h
 #define WTF_OwnPtr_h
 
+#include "wtf/Allocator.h"
 #include "wtf/HashTableDeletedValueType.h"
 #include "wtf/Noncopyable.h"
 #include "wtf/OwnPtrCommon.h"
@@ -33,6 +34,7 @@
 template <typename T> class PassOwnPtr;
 
 template <typename T> class OwnPtr {
+    USING_FAST_MALLOC(OwnPtr);
     WTF_MAKE_NONCOPYABLE(OwnPtr);
 public:
     typedef typename std::remove_extent<T>::type ValueType;
diff --git a/third_party/WebKit/Source/wtf/OwnPtrCommon.h b/third_party/WebKit/Source/wtf/OwnPtrCommon.h
index 301629e..89e24895 100644
--- a/third_party/WebKit/Source/wtf/OwnPtrCommon.h
+++ b/third_party/WebKit/Source/wtf/OwnPtrCommon.h
@@ -39,12 +39,14 @@
 
 template<typename T>
 struct IsRefCounted {
+    STATIC_ONLY(IsRefCounted);
     static const bool value = IsSubclass<T, RefCountedBase>::value
         || IsSubclass<T, ThreadSafeRefCountedBase>::value;
 };
 
 template <typename T>
 struct OwnedPtrDeleter {
+    STATIC_ONLY(OwnedPtrDeleter);
     static void deletePtr(T* ptr)
     {
         static_assert(!IsRefCounted<T>::value, "use RefPtr for RefCounted objects");
@@ -55,6 +57,7 @@
 
 template <typename T>
 struct OwnedPtrDeleter<T[]> {
+    STATIC_ONLY(OwnedPtrDeleter);
     static void deletePtr(T* ptr)
     {
         static_assert(!IsRefCounted<T>::value, "use RefPtr for RefCounted objects");
@@ -65,6 +68,7 @@
 
 template <class T, int n>
 struct OwnedPtrDeleter<T[n]> {
+    STATIC_ONLY(OwnedPtrDeleter);
     static_assert(sizeof(T) < 0, "do not use array with size as type");
 };
 
diff --git a/third_party/WebKit/Source/wtf/PartitionAllocator.h b/third_party/WebKit/Source/wtf/PartitionAllocator.h
index bf6bcb0..e3b57e5 100644
--- a/third_party/WebKit/Source/wtf/PartitionAllocator.h
+++ b/third_party/WebKit/Source/wtf/PartitionAllocator.h
@@ -186,6 +186,7 @@
 // The Windows compiler seems to be very eager to instantiate things it won't
 // need, so unless we have this class we get compile errors.
 class PartitionAllocatorDummyVisitor {
+    DISALLOW_NEW();
 public:
     template<typename T> inline bool isHeapObjectAlive(T obj)
     {
diff --git a/third_party/WebKit/Source/wtf/PassOwnPtr.h b/third_party/WebKit/Source/wtf/PassOwnPtr.h
index cde4559..ad3190d 100644
--- a/third_party/WebKit/Source/wtf/PassOwnPtr.h
+++ b/third_party/WebKit/Source/wtf/PassOwnPtr.h
@@ -27,6 +27,8 @@
 #ifndef WTF_PassOwnPtr_h
 #define WTF_PassOwnPtr_h
 
+#include "wtf/Allocator.h"
+#include "wtf/Noncopyable.h"
 #include "wtf/OwnPtrCommon.h"
 
 namespace WTF {
@@ -37,6 +39,7 @@
 template <typename T> PassOwnPtr<T[]> adoptArrayPtr(T*);
 
 template <typename T> class PassOwnPtr {
+    DISALLOW_NEW();
 public:
     typedef typename std::remove_extent<T>::type ValueType;
     typedef ValueType* PtrType;
@@ -74,35 +77,15 @@
 private:
     explicit PassOwnPtr(PtrType ptr) : m_ptr(ptr) {}
 
-    PassOwnPtr& operator=(const PassOwnPtr&)
-    {
-        static_assert(!sizeof(T*), "PassOwnPtr should never be assigned to");
-        return *this;
-    }
+    PassOwnPtr& operator=(const PassOwnPtr&) = delete;
 
     // We should never have two OwnPtrs for the same underlying object
     // (otherwise we'll get double-destruction), so these equality operators
     // should never be needed.
-    template <typename U> bool operator==(const PassOwnPtr<U>&) const
-    {
-        static_assert(!sizeof(U*), "OwnPtrs should never be equal");
-        return false;
-    }
-    template <typename U> bool operator!=(const PassOwnPtr<U>&) const
-    {
-        static_assert(!sizeof(U*), "OwnPtrs should never be equal");
-        return false;
-    }
-    template <typename U> bool operator==(const OwnPtr<U>&) const
-    {
-        static_assert(!sizeof(U*), "OwnPtrs should never be equal");
-        return false;
-    }
-    template <typename U> bool operator!=(const OwnPtr<U>&) const
-    {
-        static_assert(!sizeof(U*), "OwnPtrs should never be equal");
-        return false;
-    }
+    template <typename U> bool operator==(const PassOwnPtr<U>&) const = delete;
+    template <typename U> bool operator!=(const PassOwnPtr<U>&) const = delete;
+    template <typename U> bool operator==(const OwnPtr<U>&) const = delete;
+    template <typename U> bool operator!=(const OwnPtr<U>&) const = delete;
 
     mutable PtrType m_ptr;
 };
diff --git a/third_party/WebKit/Source/wtf/PassRefPtr.h b/third_party/WebKit/Source/wtf/PassRefPtr.h
index 8fce6bb..60c91e6 100644
--- a/third_party/WebKit/Source/wtf/PassRefPtr.h
+++ b/third_party/WebKit/Source/wtf/PassRefPtr.h
@@ -21,6 +21,7 @@
 #ifndef WTF_PassRefPtr_h
 #define WTF_PassRefPtr_h
 
+#include "wtf/Allocator.h"
 #include "wtf/Assertions.h"
 #include "wtf/RawPtr.h"
 #include "wtf/TypeTraits.h"
@@ -56,6 +57,7 @@
 }
 
 template <typename T> class PassRefPtr {
+    DISALLOW_NEW_EXCEPT_PLACEMENT_NEW();
 public:
     PassRefPtr() : m_ptr(nullptr) {}
     PassRefPtr(std::nullptr_t) : m_ptr(nullptr) {}
diff --git a/third_party/WebKit/Source/wtf/PrintStream.h b/third_party/WebKit/Source/wtf/PrintStream.h
index 4d6888b..27bd33e7 100644
--- a/third_party/WebKit/Source/wtf/PrintStream.h
+++ b/third_party/WebKit/Source/wtf/PrintStream.h
@@ -87,7 +87,8 @@
 }
 
 #define MAKE_PRINT_ADAPTOR(Name, Type, function) \
-    class Name {                                 \
+    class Name final {                           \
+        STACK_ALLOCATED();                       \
     public:                                      \
         Name(const Type& value)                  \
             : m_value(value)                     \
@@ -102,7 +103,8 @@
     }
 
 #define MAKE_PRINT_METHOD_ADAPTOR(Name, Type, method) \
-    class Name {                                 \
+    class Name final {                           \
+        STACK_ALLOCATED();                       \
     public:                                      \
         Name(const Type& value)                  \
             : m_value(value)                     \
@@ -127,7 +129,8 @@
 MAKE_PRINT_ADAPTOR(CharacterDump, char, dumpCharacter);
 
 template <typename T>
-class PointerDump {
+class PointerDump final {
+    STACK_ALLOCATED();
 public:
     PointerDump(const T* ptr)
         : m_ptr(ptr)
diff --git a/third_party/WebKit/Source/wtf/RawPtr.h b/third_party/WebKit/Source/wtf/RawPtr.h
index c3a82ec4..a666873 100644
--- a/third_party/WebKit/Source/wtf/RawPtr.h
+++ b/third_party/WebKit/Source/wtf/RawPtr.h
@@ -31,6 +31,7 @@
 #ifndef WTF_RawPtr_h
 #define WTF_RawPtr_h
 
+#include "wtf/Allocator.h"
 #include "wtf/HashTableDeletedValueType.h"
 #include "wtf/TypeTraits.h"
 #include <algorithm>
@@ -48,6 +49,7 @@
 
 template<typename T>
 class RawPtr {
+    USING_FAST_MALLOC(RawPtr);
 public:
     RawPtr()
     {
diff --git a/third_party/WebKit/Source/wtf/RefPtr.h b/third_party/WebKit/Source/wtf/RefPtr.h
index 3ccc3a8f..1737fad 100644
--- a/third_party/WebKit/Source/wtf/RefPtr.h
+++ b/third_party/WebKit/Source/wtf/RefPtr.h
@@ -23,6 +23,7 @@
 #ifndef WTF_RefPtr_h
 #define WTF_RefPtr_h
 
+#include "wtf/Allocator.h"
 #include "wtf/HashTableDeletedValueType.h"
 #include "wtf/PassRefPtr.h"
 #include "wtf/RawPtr.h"
@@ -35,6 +36,7 @@
 template <typename T> class RefPtrValuePeeker;
 
 template <typename T> class RefPtr {
+    USING_FAST_MALLOC(RefPtr);
 public:
     ALWAYS_INLINE RefPtr() : m_ptr(nullptr) {}
     ALWAYS_INLINE RefPtr(std::nullptr_t) : m_ptr(nullptr) {}
@@ -161,6 +163,7 @@
 }
 
 template <typename T> class RefPtrValuePeeker {
+    DISALLOW_NEW();
 public:
     ALWAYS_INLINE RefPtrValuePeeker(T* p): m_ptr(p) {}
     ALWAYS_INLINE RefPtrValuePeeker(std::nullptr_t): m_ptr(nullptr) {}
diff --git a/third_party/WebKit/Source/wtf/StringHasher.h b/third_party/WebKit/Source/wtf/StringHasher.h
index a43d0a7..c4fed75 100644
--- a/third_party/WebKit/Source/wtf/StringHasher.h
+++ b/third_party/WebKit/Source/wtf/StringHasher.h
@@ -22,6 +22,7 @@
 #ifndef WTF_StringHasher_h
 #define WTF_StringHasher_h
 
+#include "wtf/Allocator.h"
 #include "wtf/text/Unicode.h"
 
 namespace WTF {
@@ -38,6 +39,7 @@
 static const unsigned stringHashingStartValue = 0x9E3779B9U;
 
 class StringHasher {
+    DISALLOW_NEW();
 public:
     static const unsigned flagCount = 8; // Save 8 bits for StringImpl to use as flags.
 
diff --git a/third_party/WebKit/Source/wtf/TerminatedArray.h b/third_party/WebKit/Source/wtf/TerminatedArray.h
index 5b867143..6daba4bd 100644
--- a/third_party/WebKit/Source/wtf/TerminatedArray.h
+++ b/third_party/WebKit/Source/wtf/TerminatedArray.h
@@ -16,13 +16,15 @@
 // TerminatedArray<T> can only be constructed by TerminatedArrayBuilder<T>.
 template<typename T>
 class TerminatedArray {
+    DISALLOW_NEW();
     WTF_MAKE_NONCOPYABLE(TerminatedArray);
 public:
     T& at(size_t index) { return reinterpret_cast<T*>(this)[index]; }
     const T& at(size_t index) const { return reinterpret_cast<const T*>(this)[index]; }
 
     template<typename U>
-    class iterator_base {
+    class iterator_base final {
+        STACK_ALLOCATED();
     public:
         iterator_base& operator++()
         {
@@ -71,6 +73,7 @@
     // Allocator describes how TerminatedArrayBuilder should create new instances
     // of TerminateArray and manage their lifetimes.
     struct Allocator {
+        STATIC_ONLY(Allocator);
         typedef PassOwnPtr<TerminatedArray> PassPtr;
         typedef OwnPtr<TerminatedArray> Ptr;
 
diff --git a/third_party/WebKit/Source/wtf/ThreadSpecific.h b/third_party/WebKit/Source/wtf/ThreadSpecific.h
index cbc6b22c..2e82293b 100644
--- a/third_party/WebKit/Source/wtf/ThreadSpecific.h
+++ b/third_party/WebKit/Source/wtf/ThreadSpecific.h
@@ -42,6 +42,7 @@
 #ifndef WTF_ThreadSpecific_h
 #define WTF_ThreadSpecific_h
 
+#include "wtf/Allocator.h"
 #include "wtf/Noncopyable.h"
 #include "wtf/Partitions.h"
 #include "wtf/StdLibExtras.h"
@@ -63,6 +64,7 @@
 #endif
 
 template<typename T> class ThreadSpecific {
+    USING_FAST_MALLOC(ThreadSpecific);
     WTF_MAKE_NONCOPYABLE(ThreadSpecific);
 public:
     ThreadSpecific();
diff --git a/third_party/WebKit/Source/wtf/ThreadSpecificWin.cpp b/third_party/WebKit/Source/wtf/ThreadSpecificWin.cpp
index 6ed83652..da2e0d4a 100644
--- a/third_party/WebKit/Source/wtf/ThreadSpecificWin.cpp
+++ b/third_party/WebKit/Source/wtf/ThreadSpecificWin.cpp
@@ -25,6 +25,7 @@
 
 #include "StdLibExtras.h"
 #include "ThreadingPrimitives.h"
+#include "wtf/Allocator.h"
 #include "wtf/DoublyLinkedList.h"
 
 namespace WTF {
@@ -42,6 +43,8 @@
 }
 
 class PlatformThreadSpecificKey : public DoublyLinkedListNode<PlatformThreadSpecificKey> {
+    USING_FAST_MALLOC(PlatformThreadSpecificKey);
+    WTF_MAKE_NONCOPYABLE(PlatformThreadSpecificKey);
 public:
     friend class DoublyLinkedListNode<PlatformThreadSpecificKey>;
 
diff --git a/third_party/WebKit/Source/wtf/ThreadingPrimitives.h b/third_party/WebKit/Source/wtf/ThreadingPrimitives.h
index 0229d35..f5b8d75 100644
--- a/third_party/WebKit/Source/wtf/ThreadingPrimitives.h
+++ b/third_party/WebKit/Source/wtf/ThreadingPrimitives.h
@@ -110,7 +110,8 @@
 
 typedef Locker<MutexBase> MutexLocker;
 
-class MutexTryLocker {
+class MutexTryLocker final {
+    STACK_ALLOCATED();
     WTF_MAKE_NONCOPYABLE(MutexTryLocker);
 public:
     MutexTryLocker(Mutex& mutex) : m_mutex(mutex), m_locked(mutex.tryLock()) { }
@@ -127,7 +128,8 @@
     bool m_locked;
 };
 
-class WTF_EXPORT ThreadCondition {
+class WTF_EXPORT ThreadCondition final {
+    USING_FAST_MALLOC(ThreadCondition); // Only HeapTest.cpp requires.
     WTF_MAKE_NONCOPYABLE(ThreadCondition);
 public:
     ThreadCondition();
diff --git a/third_party/WebKit/Source/wtf/Vector.h b/third_party/WebKit/Source/wtf/Vector.h
index c9a2e659..73301493 100644
--- a/third_party/WebKit/Source/wtf/Vector.h
+++ b/third_party/WebKit/Source/wtf/Vector.h
@@ -60,11 +60,13 @@
 
 template <typename T>
 struct VectorDestructor<false, T> {
+    STATIC_ONLY(VectorDestructor);
     static void destruct(T*, T*) {}
 };
 
 template <typename T>
 struct VectorDestructor<true, T> {
+    STATIC_ONLY(VectorDestructor);
     static void destruct(T* begin, T* end)
     {
         for (T* cur = begin; cur != end; ++cur)
@@ -77,6 +79,7 @@
 
 template <typename T>
 struct VectorUnusedSlotClearer<false, T> {
+    STATIC_ONLY(VectorUnusedSlotClearer);
     static void clear(T*, T*) {}
 #if ENABLE(ASSERT)
     static void checkCleared(const T*, const T*) {}
@@ -85,6 +88,7 @@
 
 template <typename T>
 struct VectorUnusedSlotClearer<true, T> {
+    STATIC_ONLY(VectorUnusedSlotClearer);
     static void clear(T* begin, T* end)
     {
         memset(reinterpret_cast<void*>(begin), 0, sizeof(T) * (end - begin));
@@ -107,6 +111,7 @@
 
 template <typename T>
 struct VectorInitializer<false, T> {
+    STATIC_ONLY(VectorInitializer);
     static void initialize(T* begin, T* end)
     {
         for (T* cur = begin; cur != end; ++cur)
@@ -116,6 +121,7 @@
 
 template <typename T>
 struct VectorInitializer<true, T> {
+    STATIC_ONLY(VectorInitializer);
     static void initialize(T* begin, T* end)
     {
         memset(begin, 0, reinterpret_cast<char*>(end) - reinterpret_cast<char*>(begin));
@@ -127,6 +133,7 @@
 
 template <typename T>
 struct VectorMover<false, T> {
+    STATIC_ONLY(VectorMover);
     static void move(T* src, T* srcEnd, T* dst)
     {
         while (src != srcEnd) {
@@ -158,6 +165,7 @@
 
 template <typename T>
 struct VectorMover<true, T> {
+    STATIC_ONLY(VectorMover);
     static void move(const T* src, const T* srcEnd, T* dst)
     {
         if (LIKELY(dst && src))
@@ -179,6 +187,7 @@
 
 template <typename T>
 struct VectorCopier<false, T> {
+    STATIC_ONLY(VectorCopier);
     template <typename U>
     static void uninitializedCopy(const U* src, const U* srcEnd, T* dst)
     {
@@ -192,6 +201,7 @@
 
 template <typename T>
 struct VectorCopier<true, T> {
+    STATIC_ONLY(VectorCopier);
     static void uninitializedCopy(const T* src, const T* srcEnd, T* dst)
     {
         if (LIKELY(dst && src))
@@ -209,6 +219,7 @@
 
 template <typename T>
 struct VectorFiller<false, T> {
+    STATIC_ONLY(VectorFiller);
     static void uninitializedFill(T* dst, T* dstEnd, const T& val)
     {
         while (dst != dstEnd) {
@@ -220,6 +231,7 @@
 
 template <typename T>
 struct VectorFiller<true, T> {
+    STATIC_ONLY(VectorFiller);
     static void uninitializedFill(T* dst, T* dstEnd, const T& val)
     {
         static_assert(sizeof(T) == sizeof(char), "size of type should be one");
@@ -237,6 +249,7 @@
 
 template <typename T>
 struct VectorComparer<false, T> {
+    STATIC_ONLY(VectorComparer);
     static bool compare(const T* a, const T* b, size_t size)
     {
         ASSERT(a);
@@ -247,6 +260,7 @@
 
 template <typename T>
 struct VectorComparer<true, T> {
+    STATIC_ONLY(VectorComparer);
     static bool compare(const T* a, const T* b, size_t size)
     {
         ASSERT(a);
@@ -257,6 +271,7 @@
 
 template <typename T>
 struct VectorTypeOperations {
+    STATIC_ONLY(VectorTypeOperations);
     static void destruct(T* begin, T* end)
     {
         VectorDestructor<VectorTraits<T>::needsDestruction, T>::destruct(begin, end);
@@ -301,6 +316,7 @@
 template <typename T, bool hasInlineCapacity, typename Allocator>
 class VectorBufferBase {
     WTF_MAKE_NONCOPYABLE(VectorBufferBase);
+    DISALLOW_NEW();
 public:
     void allocateBuffer(size_t newCapacity)
     {
@@ -1349,6 +1365,7 @@
 #if !ENABLE(OILPAN)
 template <typename T, size_t N>
 struct NeedsTracing<Vector<T, N>> {
+    STATIC_ONLY(NeedsTracing);
     static const bool value = false;
 };
 #endif
diff --git a/third_party/WebKit/Source/wtf/WTFThreadData.h b/third_party/WebKit/Source/wtf/WTFThreadData.h
index 0dbd7e7..41526e2c 100644
--- a/third_party/WebKit/Source/wtf/WTFThreadData.h
+++ b/third_party/WebKit/Source/wtf/WTFThreadData.h
@@ -43,6 +43,7 @@
 typedef void (*AtomicStringTableDestructor)(AtomicStringTable*);
 
 class WTF_EXPORT WTFThreadData {
+    DISALLOW_NEW_EXCEPT_PLACEMENT_NEW();
     WTF_MAKE_NONCOPYABLE(WTFThreadData);
 public:
     WTFThreadData();
diff --git a/third_party/WebKit/Source/wtf/text/AtomicString.cpp b/third_party/WebKit/Source/wtf/text/AtomicString.cpp
index 88a80d6..723d8bd69 100644
--- a/third_party/WebKit/Source/wtf/text/AtomicString.cpp
+++ b/third_party/WebKit/Source/wtf/text/AtomicString.cpp
@@ -36,6 +36,7 @@
 static_assert(sizeof(AtomicString) == sizeof(String), "AtomicString and String must be same size");
 
 class AtomicStringTable {
+    USING_FAST_MALLOC(AtomicStringTable);
     WTF_MAKE_NONCOPYABLE(AtomicStringTable);
 public:
     static AtomicStringTable* create(WTFThreadData& data)
diff --git a/third_party/WebKit/Source/wtf/text/StringBuffer.h b/third_party/WebKit/Source/wtf/text/StringBuffer.h
index f38e0cf..bca6c47 100644
--- a/third_party/WebKit/Source/wtf/text/StringBuffer.h
+++ b/third_party/WebKit/Source/wtf/text/StringBuffer.h
@@ -29,6 +29,7 @@
 #ifndef StringBuffer_h
 #define StringBuffer_h
 
+#include "wtf/Allocator.h"
 #include "wtf/Assertions.h"
 #include "wtf/text/StringImpl.h"
 #include "wtf/text/Unicode.h"
@@ -37,6 +38,7 @@
 
 template <typename CharType>
 class StringBuffer {
+    DISALLOW_NEW();
     WTF_MAKE_NONCOPYABLE(StringBuffer);
 public:
     StringBuffer() { }
diff --git a/third_party/WebKit/Source/wtf/text/StringConcatenate.h b/third_party/WebKit/Source/wtf/text/StringConcatenate.h
index 01e1463..70bb0bd 100644
--- a/third_party/WebKit/Source/wtf/text/StringConcatenate.h
+++ b/third_party/WebKit/Source/wtf/text/StringConcatenate.h
@@ -26,6 +26,7 @@
 #ifndef StringConcatenate_h
 #define StringConcatenate_h
 
+#include "wtf/Allocator.h"
 #include <string.h>
 
 #ifndef WTFString_h
@@ -42,10 +43,12 @@
 
 template<typename StringType>
 class StringTypeAdapter {
+    DISALLOW_NEW();
 };
 
 template<>
 class StringTypeAdapter<char> {
+    DISALLOW_NEW();
 public:
     StringTypeAdapter<char>(char buffer)
         : m_buffer(buffer)
@@ -69,6 +72,7 @@
 
 template<>
 class StringTypeAdapter<LChar> {
+    DISALLOW_NEW();
 public:
     StringTypeAdapter<LChar>(LChar buffer)
         : m_buffer(buffer)
@@ -92,6 +96,7 @@
 
 template<>
 class StringTypeAdapter<UChar> {
+    DISALLOW_NEW();
 public:
     StringTypeAdapter<UChar>(UChar buffer)
         : m_buffer(buffer)
@@ -116,6 +121,7 @@
 
 template<>
 class WTF_EXPORT StringTypeAdapter<char*> {
+    DISALLOW_NEW();
 public:
     StringTypeAdapter<char*>(char* buffer)
         : m_buffer(buffer)
@@ -138,6 +144,7 @@
 
 template<>
 class WTF_EXPORT StringTypeAdapter<LChar*> {
+    DISALLOW_NEW();
 public:
     StringTypeAdapter<LChar*>(LChar* buffer);
 
@@ -156,6 +163,7 @@
 
 template<>
 class WTF_EXPORT StringTypeAdapter<const UChar*> {
+    DISALLOW_NEW();
 public:
     StringTypeAdapter(const UChar* buffer);
 
@@ -177,6 +185,7 @@
 
 template<>
 class WTF_EXPORT StringTypeAdapter<const char*> {
+    DISALLOW_NEW();
 public:
     StringTypeAdapter<const char*>(const char* buffer);
 
@@ -195,6 +204,7 @@
 
 template<>
 class WTF_EXPORT StringTypeAdapter<const LChar*> {
+    DISALLOW_NEW();
 public:
     StringTypeAdapter<const LChar*>(const LChar* buffer);
 
@@ -213,6 +223,7 @@
 
 template<>
 class WTF_EXPORT StringTypeAdapter<Vector<char>> {
+    DISALLOW_NEW();
 public:
     StringTypeAdapter<Vector<char>>(const Vector<char>& buffer)
         : m_buffer(buffer)
@@ -233,6 +244,7 @@
 
 template<>
 class StringTypeAdapter<Vector<LChar>> {
+    DISALLOW_NEW();
 public:
     StringTypeAdapter<Vector<LChar>>(const Vector<LChar>& buffer)
         : m_buffer(buffer)
@@ -253,6 +265,7 @@
 
 template<>
 class WTF_EXPORT StringTypeAdapter<String> {
+    DISALLOW_NEW();
 public:
     StringTypeAdapter<String>(const String& string)
         : m_buffer(string)
@@ -273,6 +286,7 @@
 
 template<>
 class StringTypeAdapter<AtomicString> {
+    DISALLOW_NEW();
 public:
     StringTypeAdapter<AtomicString>(const AtomicString& string)
         : m_adapter(string.string())
diff --git a/third_party/WebKit/Source/wtf/text/StringHash.h b/third_party/WebKit/Source/wtf/text/StringHash.h
index d10554f..7f0fcb2 100644
--- a/third_party/WebKit/Source/wtf/text/StringHash.h
+++ b/third_party/WebKit/Source/wtf/text/StringHash.h
@@ -22,6 +22,7 @@
 #ifndef StringHash_h
 #define StringHash_h
 
+#include "wtf/Allocator.h"
 #include "wtf/HashTraits.h"
 #include "wtf/StringHasher.h"
 #include "wtf/text/AtomicString.h"
@@ -43,6 +44,7 @@
 // place.
 
 struct StringHash {
+    STATIC_ONLY(StringHash);
     static unsigned hash(StringImpl* key) { return key->hash(); }
     static inline bool equal(const StringImpl* a, const StringImpl* b)
     {
@@ -65,6 +67,7 @@
 };
 
 class CaseFoldingHash {
+    STATIC_ONLY(CaseFoldingHash);
 public:
     static unsigned hash(const UChar* data, unsigned length)
     {
@@ -141,6 +144,7 @@
 // don't want to store the string. It's not really specific to string hashing,
 // but all our current uses of it are for strings.
 struct AlreadyHashed : IntHash<unsigned> {
+    STATIC_ONLY(AlreadyHashed);
     static unsigned hash(unsigned key) { return key; }
 
     // To use a hash value as a key for a hash table, we need to eliminate the
diff --git a/third_party/WebKit/Source/wtf/text/StringImpl.cpp b/third_party/WebKit/Source/wtf/text/StringImpl.cpp
index a7565fd7..2a46f3bd 100644
--- a/third_party/WebKit/Source/wtf/text/StringImpl.cpp
+++ b/third_party/WebKit/Source/wtf/text/StringImpl.cpp
@@ -900,7 +900,8 @@
     return create(characters16() + start, end + 1 - start);
 }
 
-class UCharPredicate {
+class UCharPredicate final {
+    STACK_ALLOCATED();
 public:
     inline UCharPredicate(CharacterMatchFunctionPtr function): m_function(function) { }
 
@@ -913,7 +914,8 @@
     const CharacterMatchFunctionPtr m_function;
 };
 
-class SpaceOrNewlinePredicate {
+class SpaceOrNewlinePredicate final {
+    STACK_ALLOCATED();
 public:
     inline bool operator()(UChar ch) const
     {
diff --git a/third_party/WebKit/Source/wtf/text/StringOperators.h b/third_party/WebKit/Source/wtf/text/StringOperators.h
index b2e5385f..9100cda 100644
--- a/third_party/WebKit/Source/wtf/text/StringOperators.h
+++ b/third_party/WebKit/Source/wtf/text/StringOperators.h
@@ -22,12 +22,14 @@
 #ifndef StringOperators_h
 #define StringOperators_h
 
-#include "StringConcatenate.h"
+#include "wtf/Allocator.h"
+#include "wtf/text/StringConcatenate.h"
 
 namespace WTF {
 
 template<typename StringType1, typename StringType2>
-class StringAppend {
+class StringAppend final {
+    STACK_ALLOCATED();
 public:
     StringAppend(StringType1 string1, StringType2 string2);
 
@@ -104,6 +106,7 @@
 
 template<typename StringType1, typename StringType2>
 class StringTypeAdapter<StringAppend<StringType1, StringType2>> {
+    STACK_ALLOCATED();
 public:
     StringTypeAdapter<StringAppend<StringType1, StringType2>>(StringAppend<StringType1, StringType2>& buffer)
         : m_buffer(buffer)
diff --git a/third_party/WebKit/Source/wtf/text/StringStatics.h b/third_party/WebKit/Source/wtf/text/StringStatics.h
index b241894..e2c34dda 100644
--- a/third_party/WebKit/Source/wtf/text/StringStatics.h
+++ b/third_party/WebKit/Source/wtf/text/StringStatics.h
@@ -31,16 +31,15 @@
 #ifndef StringStatics_h
 #define StringStatics_h
 
+#include "wtf/Allocator.h"
 #include "wtf/WTFExport.h"
 
 namespace WTF {
 
 class StringStatics {
+    STATIC_ONLY(StringStatics);
 public:
     WTF_EXPORT static void init();
-
-private:
-    StringStatics();
 };
 
 }
diff --git a/third_party/WebKit/Source/wtf/text/StringUTF8Adaptor.h b/third_party/WebKit/Source/wtf/text/StringUTF8Adaptor.h
index 10928b3..e330c85a 100644
--- a/third_party/WebKit/Source/wtf/text/StringUTF8Adaptor.h
+++ b/third_party/WebKit/Source/wtf/text/StringUTF8Adaptor.h
@@ -32,6 +32,7 @@
 #define StringUTF8Adaptor_h
 
 #include "base/strings/string_piece.h"
+#include "wtf/Allocator.h"
 #include "wtf/text/CString.h"
 #include "wtf/text/TextEncoding.h"
 #include "wtf/text/WTFString.h"
@@ -41,7 +42,8 @@
 // This class lets you get UTF-8 data out of a String without mallocing a
 // separate buffer to hold the data if the String happens to be 8 bit and
 // contain only ASCII characters.
-class StringUTF8Adaptor {
+class StringUTF8Adaptor final {
+    DISALLOW_NEW();
 public:
     explicit StringUTF8Adaptor(const String& string)
         : m_data(0)
diff --git a/third_party/WebKit/Source/wtf/text/StringView.h b/third_party/WebKit/Source/wtf/text/StringView.h
index dc92fa3..40b0b94 100644
--- a/third_party/WebKit/Source/wtf/text/StringView.h
+++ b/third_party/WebKit/Source/wtf/text/StringView.h
@@ -31,11 +31,13 @@
 #ifndef WTF_StringView_h
 #define WTF_StringView_h
 
+#include "wtf/Allocator.h"
 #include "wtf/text/StringImpl.h"
 
 namespace WTF {
 
 class WTF_EXPORT StringView {
+    DISALLOW_NEW();
 public:
     StringView()
         : m_offset(0)
diff --git a/third_party/WebKit/Source/wtf/text/TextCodecICU.cpp b/third_party/WebKit/Source/wtf/text/TextCodecICU.cpp
index c63669e1..f90d447c 100644
--- a/third_party/WebKit/Source/wtf/text/TextCodecICU.cpp
+++ b/third_party/WebKit/Source/wtf/text/TextCodecICU.cpp
@@ -305,7 +305,8 @@
     return target - targetStart;
 }
 
-class ErrorCallbackSetter {
+class ErrorCallbackSetter final {
+    STACK_ALLOCATED();
 public:
     ErrorCallbackSetter(UConverter* converter, bool stopOnError)
         : m_converter(converter)
@@ -473,7 +474,8 @@
 }
 #endif // USING_SYSTEM_ICU
 
-class TextCodecInput {
+class TextCodecInput final {
+    STACK_ALLOCATED();
 public:
     TextCodecInput(const TextEncoding& encoding, const UChar* characters, size_t length)
         : m_begin(characters)
diff --git a/third_party/WebKit/Source/wtf/text/TextEncoding.h b/third_party/WebKit/Source/wtf/text/TextEncoding.h
index bb40b961..1b97e13 100644
--- a/third_party/WebKit/Source/wtf/text/TextEncoding.h
+++ b/third_party/WebKit/Source/wtf/text/TextEncoding.h
@@ -26,6 +26,7 @@
 #ifndef TextEncoding_h
 #define TextEncoding_h
 
+#include "wtf/Allocator.h"
 #include "wtf/Forward.h"
 #include "wtf/WTFExport.h"
 #include "wtf/text/TextCodec.h"
@@ -33,7 +34,8 @@
 
 namespace WTF {
 
-class WTF_EXPORT TextEncoding {
+class WTF_EXPORT TextEncoding final {
+    USING_FAST_MALLOC(TextEncoding);
 public:
     TextEncoding() : m_name(0) { }
     TextEncoding(const char* name);
diff --git a/third_party/WebKit/Source/wtf/text/TextPosition.h b/third_party/WebKit/Source/wtf/text/TextPosition.h
index 8626054b..17140c3 100644
--- a/third_party/WebKit/Source/wtf/text/TextPosition.h
+++ b/third_party/WebKit/Source/wtf/text/TextPosition.h
@@ -25,6 +25,7 @@
 #ifndef TextPosition_h
 #define TextPosition_h
 
+#include "wtf/Allocator.h"
 #include "wtf/Assertions.h"
 #include "wtf/Vector.h"
 #include "wtf/WTFExport.h"
@@ -35,7 +36,8 @@
 // An abstract number of element in a sequence. The sequence has a first element.
 // This type should be used instead of integer because 2 contradicting traditions can
 // call a first element '0' or '1' which makes integer type ambiguous.
-class OrdinalNumber {
+class OrdinalNumber final {
+    DISALLOW_NEW();
 public:
     static OrdinalNumber fromZeroBasedInt(int zeroBasedInt) { return OrdinalNumber(zeroBasedInt); }
     static OrdinalNumber fromOneBasedInt(int oneBasedInt) { return OrdinalNumber(oneBasedInt - 1); }
@@ -58,7 +60,8 @@
 
 // TextPosition structure specifies coordinates within an text resource. It is used mostly
 // for saving script source position.
-class TextPosition {
+class TextPosition final {
+    DISALLOW_NEW();
 public:
     TextPosition(OrdinalNumber line, OrdinalNumber column)
         : m_line(line)
diff --git a/third_party/WebKit/public/blink_headers.gypi b/third_party/WebKit/public/blink_headers.gypi
index fcb9d72..62f4b60d 100644
--- a/third_party/WebKit/public/blink_headers.gypi
+++ b/third_party/WebKit/public/blink_headers.gypi
@@ -44,7 +44,6 @@
       "platform/WebContentLayer.h",
       "platform/WebContentLayerClient.h",
       "platform/WebContentSettingCallbacks.h",
-      "platform/WebConvertableToTraceFormat.h",
       "platform/WebCookieJar.h",
       "platform/WebCredential.h",
       "platform/WebCredentialManagerClient.h",
diff --git a/third_party/WebKit/public/platform/Platform.h b/third_party/WebKit/public/platform/Platform.h
index 166d1493..bed866e 100644
--- a/third_party/WebKit/public/platform/Platform.h
+++ b/third_party/WebKit/public/platform/Platform.h
@@ -64,7 +64,6 @@
 class WebCanvasCaptureHandler;
 class WebClipboard;
 class WebCompositorSupport;
-class WebConvertableToTraceFormat;
 class WebCookieJar;
 class WebCrypto;
 class WebDatabaseObserver;
@@ -446,107 +445,6 @@
     // Get a pointer to testing support interfaces. Will not be available in production builds.
     virtual WebUnitTestSupport* unitTestSupport() { return nullptr; }
 
-
-    // Tracing -------------------------------------------------------------
-
-    // Get a pointer to the enabled state of the given trace category. The
-    // embedder can dynamically change the enabled state as trace event
-    // recording is started and stopped by the application. Only long-lived
-    // literal strings should be given as the category name. The implementation
-    // expects the returned pointer to be held permanently in a local static. If
-    // the unsigned char is non-zero, tracing is enabled. If tracing is enabled,
-    // addTraceEvent is expected to be called by the trace event macros.
-    virtual const unsigned char* getTraceCategoryEnabledFlag(const char* categoryName) { return nullptr; }
-
-    typedef intptr_t TraceEventAPIAtomicWord;
-
-    // Get a pointer to a global state of the given thread. An embedder is
-    // expected to update the global state as the state of the embedder changes.
-    // A sampling thread in the Chromium side reads the global state periodically
-    // and reflects the sampling profiled results into about:tracing.
-    virtual TraceEventAPIAtomicWord* getTraceSamplingState(const unsigned bucketName) { return nullptr; }
-
-    typedef uint64_t TraceEventHandle;
-
-    // Add a trace event to the platform tracing system. Depending on the actual
-    // enabled state, this event may be recorded or dropped.
-    // - phase specifies the type of event:
-    //   - BEGIN ('B'): Marks the beginning of a scoped event.
-    //   - END ('E'): Marks the end of a scoped event.
-    //   - COMPLETE ('X'): Marks the beginning of a scoped event, but doesn't
-    //     need a matching END event. Instead, at the end of the scope,
-    //     updateTraceEventDuration() must be called with the TraceEventHandle
-    //     returned from addTraceEvent().
-    //   - INSTANT ('I'): Standalone, instantaneous event.
-    //   - START ('S'): Marks the beginning of an asynchronous event (the end
-    //     event can occur in a different scope or thread). The id parameter is
-    //     used to match START/FINISH pairs.
-    //   - FINISH ('F'): Marks the end of an asynchronous event.
-    //   - COUNTER ('C'): Used to trace integer quantities that change over
-    //     time. The argument values are expected to be of type int.
-    //   - METADATA ('M'): Reserved for internal use.
-    // - categoryEnabled is the pointer returned by getTraceCategoryEnabledFlag.
-    // - name is the name of the event. Also used to match BEGIN/END and
-    //   START/FINISH pairs.
-    // - id optionally allows events of the same name to be distinguished from
-    //   each other. For example, to trace the consutruction and destruction of
-    //   objects, specify the pointer as the id parameter.
-    // - numArgs specifies the number of elements in argNames, argTypes, and
-    //   argValues.
-    // - argNames is the array of argument names. Use long-lived literal strings
-    //   or specify the COPY flag.
-    // - argTypes is the array of argument types:
-    //   - BOOL (1): bool
-    //   - UINT (2): unsigned long long
-    //   - INT (3): long long
-    //   - DOUBLE (4): double
-    //   - POINTER (5): void*
-    //   - STRING (6): char* (long-lived null-terminated char* string)
-    //   - COPY_STRING (7): char* (temporary null-terminated char* string)
-    //   - CONVERTABLE (8): WebConvertableToTraceFormat
-    // - argValues is the array of argument values. Each value is the unsigned
-    //   long long member of a union of all supported types.
-    // - convertableValues is the array of WebConvertableToTraceFormat classes
-    //   that may be converted to trace format by calling asTraceFormat method.
-    //   ConvertableToTraceFormat interface.
-    //   convertableValues can be moved to another object by
-    //   WebConvertableToTraceFormat::moveFrom() in addTraceEvent(), and thus
-    //   should not be dereferenced (e.g. asTraceFormat() should not be called)
-    //   after return from addTraceEvent().
-    // - thresholdBeginId optionally specifies the value returned by a previous
-    //   call to addTraceEvent with a BEGIN phase.
-    // - threshold is used on an END phase event in conjunction with the
-    //   thresholdBeginId of a prior BEGIN event. The threshold is the minimum
-    //   number of microseconds that must have passed since the BEGIN event. If
-    //   less than threshold microseconds has passed, the BEGIN/END pair is
-    //   dropped.
-    // - flags can be 0 or one or more of the following, ORed together:
-    //   - COPY (0x1): treat all strings (name, argNames and argValues of type
-    //     string) as temporary so that they will be copied by addTraceEvent.
-    //   - HAS_ID (0x2): use the id argument to uniquely identify the event for
-    //     matching with other events of the same name.
-    //   - MANGLE_ID (0x4): specify this flag if the id parameter is the value
-    //     of a pointer.
-    virtual TraceEventHandle addTraceEvent(
-        char phase,
-        const unsigned char* categoryEnabledFlag,
-        const char* name,
-        unsigned long long id,
-        unsigned long long bindId,
-        double timestamp,
-        int numArgs,
-        const char** argNames,
-        const unsigned char* argTypes,
-        const unsigned long long* argValues,
-        WebConvertableToTraceFormat* convertableValues,
-        unsigned flags)
-    {
-        return 0;
-    }
-
-    // Set the duration field of a COMPLETE trace event.
-    virtual void updateTraceEventDuration(const unsigned char* categoryEnabledFlag, const char* name, TraceEventHandle) { }
-
     // Callbacks for reporting histogram data.
     // CustomCounts histogram has exponential bucket sizes, so that min=1, max=1000000, bucketCount=50 would do.
     virtual void histogramCustomCounts(const char* name, int sample, int min, int max, int bucketCount) { }
diff --git a/third_party/WebKit/public/platform/WebConvertableToTraceFormat.h b/third_party/WebKit/public/platform/WebConvertableToTraceFormat.h
deleted file mode 100644
index aaffa05a..0000000
--- a/third_party/WebKit/public/platform/WebConvertableToTraceFormat.h
+++ /dev/null
@@ -1,43 +0,0 @@
-// Copyright 2014 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 WebConvertableToTraceFormat_h
-#define WebConvertableToTraceFormat_h
-
-#include "WebPrivatePtr.h"
-#include "WebString.h"
-
-namespace blink {
-
-namespace TraceEvent {
-class ConvertableToTraceFormat;
-}
-
-class WebConvertableToTraceFormat {
-public:
-    WebConvertableToTraceFormat() { }
-#if INSIDE_BLINK
-    WebConvertableToTraceFormat(PassRefPtr<TraceEvent::ConvertableToTraceFormat>);
-#endif
-    ~WebConvertableToTraceFormat() { reset(); }
-
-    BLINK_PLATFORM_EXPORT WebString asTraceFormat() const;
-    BLINK_PLATFORM_EXPORT void assign(const WebConvertableToTraceFormat&);
-    BLINK_PLATFORM_EXPORT void moveFrom(WebConvertableToTraceFormat&);
-    BLINK_PLATFORM_EXPORT void reset();
-
-    WebConvertableToTraceFormat(const WebConvertableToTraceFormat& r) { assign(r); }
-    WebConvertableToTraceFormat& operator=(const WebConvertableToTraceFormat& r)
-    {
-        assign(r);
-        return *this;
-    }
-
-private:
-    WebPrivatePtr<TraceEvent::ConvertableToTraceFormat> m_private;
-};
-
-} // namespace blink
-
-#endif
diff --git a/third_party/WebKit/public/platform/WebLayer.h b/third_party/WebKit/public/platform/WebLayer.h
index 6ef2535..0d401821 100644
--- a/third_party/WebKit/public/platform/WebLayer.h
+++ b/third_party/WebKit/public/platform/WebLayer.h
@@ -32,6 +32,7 @@
 #include "WebCompositorAnimation.h"
 #include "WebDoublePoint.h"
 #include "WebFloatPoint3D.h"
+#include "WebMainThreadScrollingReason.h"
 #include "WebPoint.h"
 #include "WebRect.h"
 #include "WebScrollBlocksOn.h"
@@ -207,7 +208,10 @@
     virtual void setHaveScrollEventHandlers(bool) = 0;
     virtual bool haveScrollEventHandlers() const = 0;
 
-    virtual void setShouldScrollOnMainThread(bool) = 0;
+    // Indicates that this layer will always scroll on the main thread for the provided reason.
+    virtual void addMainThreadScrollingReasons(WebMainThreadScrollingReason::WebMainThreadScrollingReason) = 0;
+    // Indicates that the layer could scroll on the compositor thread.
+    virtual void clearMainThreadScrollingReasons() = 0;
     virtual bool shouldScrollOnMainThread() const = 0;
 
     virtual void setNonFastScrollableRegion(const WebVector<WebRect>&) = 0;
diff --git a/third_party/WebKit/public/platform/WebMainThreadScrollingReason.h b/third_party/WebKit/public/platform/WebMainThreadScrollingReason.h
new file mode 100644
index 0000000..7dcae44
--- /dev/null
+++ b/third_party/WebKit/public/platform/WebMainThreadScrollingReason.h
@@ -0,0 +1,26 @@
+// 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 WebMainThreadScrollingReason_h
+#define WebMainThreadScrollingReason_h
+
+#include "WebCommon.h"
+
+namespace blink {
+
+// Ensure this stays in sync with InputHandler::MainThreadScrollingReason.
+namespace WebMainThreadScrollingReason {
+enum WebMainThreadScrollingReason {
+    NotScrollingOnMain = 0,
+    HasBackgroundAttachmentFixedObjects = 1 << 0,
+    HasNonLayerViewportConstrainedObjects = 1 << 1,
+    ThreadedScrollingDisabled = 1 << 2,
+    ScrollBarScrolling = 1 << 3,
+    PageOverlay = 1 << 4
+};
+} // namespace MainThreadScrollingReason
+
+} // namespace blink
+
+#endif
diff --git a/third_party/WebKit/public/platform/modules/serviceworker/WebServiceWorkerRequest.h b/third_party/WebKit/public/platform/modules/serviceworker/WebServiceWorkerRequest.h
index cd2caa70..4a7263d 100644
--- a/third_party/WebKit/public/platform/modules/serviceworker/WebServiceWorkerRequest.h
+++ b/third_party/WebKit/public/platform/modules/serviceworker/WebServiceWorkerRequest.h
@@ -64,6 +64,9 @@
     void setMode(WebURLRequest::FetchRequestMode);
     WebURLRequest::FetchRequestMode mode() const;
 
+    void setIsMainResourceLoad(bool);
+    bool isMainResourceLoad() const;
+
     void setCredentialsMode(WebURLRequest::FetchCredentialsMode);
     WebURLRequest::FetchCredentialsMode credentialsMode() const;
 
@@ -76,6 +79,9 @@
     void setFrameType(WebURLRequest::FrameType);
     WebURLRequest::FrameType frameType() const;
 
+    void setClientId(const WebString&);
+    WebString clientId() const;
+
     void setIsReload(bool);
     bool isReload() const;
 
diff --git a/third_party/WebKit/public/web/WebInputEvent.h b/third_party/WebKit/public/web/WebInputEvent.h
index 6ce0fea..92b6347 100644
--- a/third_party/WebKit/public/web/WebInputEvent.h
+++ b/third_party/WebKit/public/web/WebInputEvent.h
@@ -456,6 +456,12 @@
 
 class WebGestureEvent : public WebInputEvent {
 public:
+    enum ScrollUnits {
+        PrecisePixels = 0, // generated by high precision devices.
+        Pixels, // large pixel jump duration; should animate to delta.
+        Page // page (visible viewport) based scrolling.
+    };
+
     int x;
     int y;
     int globalX;
@@ -502,6 +508,8 @@
             // May be redundant with deltaX/deltaY in the first scrollUpdate.
             float deltaXHint;
             float deltaYHint;
+            // Default initialized to ScrollUnits::PrecisePixels.
+            ScrollUnits deltaHintUnits;
             // If true, this event will skip hit testing to find a scroll
             // target and instead just scroll the viewport.
             bool targetViewport;
@@ -520,6 +528,8 @@
             bool previousUpdateInSequencePrevented;
             bool preventPropagation;
             bool inertial;
+            // Default initialized to ScrollUnits::PrecisePixels.
+            ScrollUnits deltaUnits;
         } scrollUpdate;
 
         struct {
diff --git a/third_party/crashpad/README.chromium b/third_party/crashpad/README.chromium
index 92bdd99..b681fe1 100644
--- a/third_party/crashpad/README.chromium
+++ b/third_party/crashpad/README.chromium
@@ -2,7 +2,7 @@
 Short Name: crashpad
 URL: https://crashpad.chromium.org/
 Version: unknown
-Revision: 417097b91fe872404db257532d5126cfd7bfb438
+Revision: 4794225f22583a08732cb9ad4356106013a220f3
 License: Apache 2.0
 License File: crashpad/LICENSE
 Security Critical: yes
diff --git a/third_party/crashpad/crashpad/codereview.settings b/third_party/crashpad/crashpad/codereview.settings
index c3673e8..3878422 100644
--- a/third_party/crashpad/crashpad/codereview.settings
+++ b/third_party/crashpad/crashpad/codereview.settings
@@ -12,7 +12,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-CODE_REVIEW_SERVER: codereview.chromium.org
-CC_LIST: crashpad-dev@chromium.org
+GERRIT_HOST: True
+CODE_REVIEW_SERVER: https://canary-chromium-review.googlesource.com/
 VIEW_VC: https://chromium.googlesource.com/crashpad/crashpad/+/
 PROJECT: crashpad
diff --git a/third_party/crashpad/crashpad/snapshot/api/module_annotations_win.cc b/third_party/crashpad/crashpad/snapshot/api/module_annotations_win.cc
new file mode 100644
index 0000000..8f444fa
--- /dev/null
+++ b/third_party/crashpad/crashpad/snapshot/api/module_annotations_win.cc
@@ -0,0 +1,53 @@
+// Copyright 2016 The Crashpad Authors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "snapshot/api/module_annotations_win.h"
+
+#include "snapshot/win/pe_image_annotations_reader.h"
+#include "snapshot/win/pe_image_reader.h"
+#include "snapshot/win/process_reader_win.h"
+#include "util/win/get_module_information.h"
+
+namespace crashpad {
+
+bool ReadModuleAnnotations(HANDLE process,
+                           HMODULE module,
+                           std::map<std::string, std::string>* annotations) {
+  ProcessReaderWin process_reader;
+  if (!process_reader.Initialize(process, ProcessSuspensionState::kRunning))
+    return false;
+
+  MODULEINFO module_info;
+  if (!CrashpadGetModuleInformation(
+          process, module, &module_info, sizeof(module_info))) {
+    PLOG(ERROR) << "CrashpadGetModuleInformation";
+    return false;
+  }
+
+  PEImageReader image_reader;
+  if (!image_reader.Initialize(
+          &process_reader,
+          reinterpret_cast<crashpad::WinVMAddress>(module_info.lpBaseOfDll),
+          module_info.SizeOfImage,
+          ""))
+    return false;
+
+  PEImageAnnotationsReader annotations_reader(
+      &process_reader, &image_reader, L"");
+
+  *annotations = annotations_reader.SimpleMap();
+  return true;
+}
+
+}  // namespace crashpad
diff --git a/third_party/crashpad/crashpad/snapshot/api/module_annotations_win.h b/third_party/crashpad/crashpad/snapshot/api/module_annotations_win.h
new file mode 100644
index 0000000..e024031
--- /dev/null
+++ b/third_party/crashpad/crashpad/snapshot/api/module_annotations_win.h
@@ -0,0 +1,42 @@
+// Copyright 2016 The Crashpad Authors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef CRASHPAD_SNAPSHOT_API_MODULE_ANNOTATIONS_WIN_H_
+#define CRASHPAD_SNAPSHOT_API_MODULE_ANNOTATIONS_WIN_H_
+
+#include <windows.h>
+
+#include <map>
+#include <string>
+
+namespace crashpad {
+
+//! \brief Reads the module annotations from another process.
+//!
+//! \param[in] process The handle to the process that hosts the \a module.
+//!     Requires PROCESS_QUERY_INFORMATION and PROCESS_VM_READ accesses.
+//! \param[in] module The handle to the module from which the \a annotations
+//!     will be read. This module should be loaded in the target process.
+//! \param[out] annotations The map that will be filled with the annotations.
+//!     Remains unchanged if the function returns 'false'.
+//!
+//! \return `true` if the annotations could be read succesfully, even if the
+//!     module doesn't contain any annotations.
+bool ReadModuleAnnotations(HANDLE process,
+                           HMODULE module,
+                           std::map<std::string, std::string>* annotations);
+
+}  // namespace crashpad
+
+#endif  // CRASHPAD_SNAPSHOT_API_MODULE_ANNOTATIONS_WIN_H_
diff --git a/third_party/crashpad/crashpad/snapshot/api/module_annotations_win_test.cc b/third_party/crashpad/crashpad/snapshot/api/module_annotations_win_test.cc
new file mode 100644
index 0000000..30e880f3
--- /dev/null
+++ b/third_party/crashpad/crashpad/snapshot/api/module_annotations_win_test.cc
@@ -0,0 +1,83 @@
+// Copyright 2016 The Crashpad Authors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "snapshot/api/module_annotations_win.h"
+
+#include "client/crashpad_info.h"
+#include "gtest/gtest.h"
+#include "test/win/win_multiprocess.h"
+#include "util/file/file_io.h"
+
+namespace crashpad {
+namespace test {
+namespace {
+
+class ModuleAnnotationsMultiprocessTest final : public WinMultiprocess {
+ private:
+  void WinMultiprocessParent() override {
+    // Read the child executable module.
+    HMODULE module = nullptr;
+    CheckedReadFile(ReadPipeHandle(), &module, sizeof(module));
+
+    // Reopen the child process with necessary access.
+    HANDLE process_handle =
+        OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
+                    FALSE,
+                    GetProcessId(ChildProcess()));
+    EXPECT_TRUE(process_handle);
+
+    // Read the module annotations in the child process and verify them.
+    std::map<std::string, std::string> annotations;
+    ASSERT_TRUE(ReadModuleAnnotations(process_handle, module, &annotations));
+
+    EXPECT_GE(annotations.size(), 3u);
+    EXPECT_EQ("value", annotations["#APITEST# key"]);
+    EXPECT_EQ("y", annotations["#APITEST# x"]);
+    EXPECT_EQ("", annotations["#APITEST# empty_value"]);
+
+    // Signal the child process to terminate.
+    char c = ' ';
+    CheckedWriteFile(WritePipeHandle(), &c, sizeof(c));
+  }
+
+  void WinMultiprocessChild() override {
+    // Set some test annotations.
+    crashpad::CrashpadInfo* crashpad_info =
+        crashpad::CrashpadInfo::GetCrashpadInfo();
+
+    crashpad::SimpleStringDictionary* simple_annotations =
+        new crashpad::SimpleStringDictionary();
+    simple_annotations->SetKeyValue("#APITEST# key", "value");
+    simple_annotations->SetKeyValue("#APITEST# x", "y");
+    simple_annotations->SetKeyValue("#APITEST# empty_value", "");
+
+    crashpad_info->set_simple_annotations(simple_annotations);
+
+    // Send the executable module.
+    HMODULE module = GetModuleHandle(nullptr);
+    CheckedWriteFile(WritePipeHandle(), &module, sizeof(module));
+
+    // Wait until a signal from the parent process to terminate.
+    char c;
+    CheckedReadFile(ReadPipeHandle(), &c, sizeof(c));
+  }
+};
+
+TEST(ModuleAnnotationsWin, ReadAnnotations) {
+  WinMultiprocess::Run<ModuleAnnotationsMultiprocessTest>();
+}
+
+}  // namespace
+}  // namespace test
+}  // namespace crashpad
diff --git a/third_party/crashpad/crashpad/snapshot/snapshot.gyp b/third_party/crashpad/crashpad/snapshot/snapshot.gyp
index 29711b06..0154495 100644
--- a/third_party/crashpad/crashpad/snapshot/snapshot.gyp
+++ b/third_party/crashpad/crashpad/snapshot/snapshot.gyp
@@ -129,5 +129,32 @@
         }],
       ]
     },
+    {
+      'variables': {
+        'conditions': [
+          ['OS == "win"', {
+            'snapshot_api_target_type%': 'static_library',
+          }, {
+            # There are no source files except on Windows.
+            'snapshot_api_target_type%': 'none',
+          }],
+        ],
+      },
+      'target_name': 'crashpad_snapshot_api',
+      'type': '<(snapshot_api_target_type)',
+      'dependencies': [
+        'crashpad_snapshot',
+        '../compat/compat.gyp:crashpad_compat',
+        '../third_party/mini_chromium/mini_chromium.gyp:base',
+        '../util/util.gyp:crashpad_util',
+      ],
+      'include_dirs': [
+        '..',
+      ],
+      'sources': [
+        'api/module_annotations_win.cc',
+        'api/module_annotations_win.h',
+      ],
+    },
   ],
 }
diff --git a/third_party/crashpad/crashpad/snapshot/snapshot_test.gyp b/third_party/crashpad/crashpad/snapshot/snapshot_test.gyp
index 51274e6c..9bfcf8b3 100644
--- a/third_party/crashpad/crashpad/snapshot/snapshot_test.gyp
+++ b/third_party/crashpad/crashpad/snapshot/snapshot_test.gyp
@@ -54,6 +54,7 @@
       'dependencies': [
         'crashpad_snapshot_test_module',
         'snapshot.gyp:crashpad_snapshot',
+        'snapshot.gyp:crashpad_snapshot_api',
         '../client/client.gyp:crashpad_client',
         '../compat/compat.gyp:crashpad_compat',
         '../test/test.gyp:crashpad_test',
@@ -68,6 +69,7 @@
       'sources': [
         'cpu_context_test.cc',
         'crashpad_info_client_options_test.cc',
+        'api/module_annotations_win_test.cc',
         'mac/cpu_context_mac_test.cc',
         'mac/mach_o_image_annotations_reader_test.cc',
         'mac/mach_o_image_reader_test.cc',
diff --git a/third_party/crashpad/crashpad/snapshot/win/pe_image_annotations_reader_test.cc b/third_party/crashpad/crashpad/snapshot/win/pe_image_annotations_reader_test.cc
index 9bdf124..523a449 100644
--- a/third_party/crashpad/crashpad/snapshot/win/pe_image_annotations_reader_test.cc
+++ b/third_party/crashpad/crashpad/snapshot/win/pe_image_annotations_reader_test.cc
@@ -31,7 +31,6 @@
 #include "snapshot/win/process_reader_win.h"
 #include "test/paths.h"
 #include "test/win/child_launcher.h"
-#include "test/win/win_multiprocess.h"
 #include "util/file/file_io.h"
 #include "util/win/process_info.h"
 
diff --git a/third_party/crashpad/crashpad/snapshot/win/pe_image_reader_test.cc b/third_party/crashpad/crashpad/snapshot/win/pe_image_reader_test.cc
index 46795cfb..704b659 100644
--- a/third_party/crashpad/crashpad/snapshot/win/pe_image_reader_test.cc
+++ b/third_party/crashpad/crashpad/snapshot/win/pe_image_reader_test.cc
@@ -22,7 +22,7 @@
 #include "gtest/gtest.h"
 #include "snapshot/win/process_reader_win.h"
 #include "test/errors.h"
-#include "util/win/get_function.h"
+#include "util/win/get_module_information.h"
 #include "util/win/module_version.h"
 #include "util/win/process_info.h"
 
@@ -32,15 +32,6 @@
 namespace test {
 namespace {
 
-BOOL CrashpadGetModuleInformation(HANDLE process,
-                                  HMODULE module,
-                                  MODULEINFO* module_info,
-                                  DWORD cb) {
-  static const auto get_module_information =
-      GET_FUNCTION_REQUIRED(L"psapi.dll", ::GetModuleInformation);
-  return get_module_information(process, module, module_info, cb);
-}
-
 TEST(PEImageReader, DebugDirectory) {
   PEImageReader pe_image_reader;
   ProcessReaderWin process_reader;
diff --git a/third_party/crashpad/crashpad/util/util.gyp b/third_party/crashpad/crashpad/util/util.gyp
index 6d0090f4..4819490 100644
--- a/third_party/crashpad/crashpad/util/util.gyp
+++ b/third_party/crashpad/crashpad/util/util.gyp
@@ -166,6 +166,8 @@
         'win/exception_handler_server.h',
         'win/get_function.cc',
         'win/get_function.h',
+        'win/get_module_information.cc',
+        'win/get_module_information.h',
         'win/handle.cc',
         'win/handle.h',
         'win/module_version.cc',
diff --git a/third_party/crashpad/crashpad/util/win/get_module_information.cc b/third_party/crashpad/crashpad/util/win/get_module_information.cc
new file mode 100644
index 0000000..1a9fd0c
--- /dev/null
+++ b/third_party/crashpad/crashpad/util/win/get_module_information.cc
@@ -0,0 +1,30 @@
+// Copyright 2016 The Crashpad Authors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "util/win/get_module_information.h"
+
+#include "util/win/get_function.h"
+
+namespace crashpad {
+
+BOOL CrashpadGetModuleInformation(HANDLE process,
+                                  HMODULE module,
+                                  MODULEINFO* module_info,
+                                  DWORD cb) {
+  static const auto get_module_information =
+      GET_FUNCTION_REQUIRED(L"psapi.dll", GetModuleInformation);
+  return get_module_information(process, module, module_info, cb);
+}
+
+}  // namespace crashpad
diff --git a/third_party/crashpad/crashpad/util/win/get_module_information.h b/third_party/crashpad/crashpad/util/win/get_module_information.h
new file mode 100644
index 0000000..c7d1cf1
--- /dev/null
+++ b/third_party/crashpad/crashpad/util/win/get_module_information.h
@@ -0,0 +1,33 @@
+// Copyright 2016 The Crashpad Authors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef CRASHPAD_UTIL_WIN_GET_MODULE_INFORMATION_H_
+#define CRASHPAD_UTIL_WIN_GET_MODULE_INFORMATION_H_
+
+#include <windows.h>
+
+#define PSAPI_VERSION 1
+#include <psapi.h>
+
+namespace crashpad {
+
+//! \brief Proxy function for `GetModuleInformation()`.
+BOOL CrashpadGetModuleInformation(HANDLE process,
+                                  HMODULE module,
+                                  MODULEINFO* module_info,
+                                  DWORD cb);
+
+}  // namespace crashpad
+
+#endif  // CRASHPAD_UTIL_WIN_GET_MODULE_INFORMATION_H_
diff --git a/third_party/libjingle/README.chromium b/third_party/libjingle/README.chromium
index c64f9b01..34a565f 100644
--- a/third_party/libjingle/README.chromium
+++ b/third_party/libjingle/README.chromium
@@ -1,7 +1,7 @@
 Name: libjingle
 URL: http://www.webrtc.org
 Version: unknown
-Revision: 11250
+Revision: 11290
 License: BSD
 License File: source/talk/COPYING
 Security Critical: yes
diff --git a/third_party/openh264/openh264.gyp b/third_party/openh264/openh264.gyp
index 4d46bfc..388e655 100644
--- a/third_party/openh264/openh264.gyp
+++ b/third_party/openh264/openh264.gyp
@@ -44,12 +44,13 @@
             # resort to using |AdditionalOptions| instead.
             'msvs_settings': {
               'VCCLCompilerTool': {
+                'AdditionalOptions': [
+                  '-Wno-unused-function',
+                  '-Wno-unused-value',
+                ],
                 'AdditionalOptions!': [
                   '-Wheader-hygiene',
                 ],
-                'AdditionalOptions': [
-                  '-Wno-unused-value',
-                ],
               },
             },
           }],
diff --git a/third_party/ots/INSTALL b/third_party/ots/INSTALL
index da35254..419a2a8 100644
--- a/third_party/ots/INSTALL
+++ b/third_party/ots/INSTALL
@@ -31,3 +31,22 @@
       $ pacman -S autoconf automake pkg-config gcc make zlib-devel
 
    3. Follow the general build instructions above.
+
+Developer build instructions:
+
+  1. If you would like to see the source code lines related to reported 
+     errors, then run make with:
+
+     $ make CXXFLAGS=-DOTS_DEBUG
+
+     For example,
+
+     $ ./ot-sanitise ~/fonts/ofl/merriweathersans/MerriweatherSans-Bold.ttf 
+     ERROR at src/layout.cc:100 (ParseScriptTable)
+     ERROR: Layout: DFLT table doesn't satisfy the spec. for script tag DFLT
+     ERROR at src/layout.cc:1247 (ParseScriptListTable)
+     ERROR: Layout: Failed to parse script table 0
+     ERROR at src/gsub.cc:642 (ots_gsub_parse)
+     ERROR: GSUB: Failed to parse script list table
+     ERROR at src/ots.cc:669 (ProcessGeneric)
+     Failed to sanitise file!
diff --git a/third_party/ots/Makefile.am b/third_party/ots/Makefile.am
index cde62aa..b1ea71c 100644
--- a/third_party/ots/Makefile.am
+++ b/third_party/ots/Makefile.am
@@ -124,7 +124,6 @@
   third_party/brotli/dec/decode.c \
   third_party/brotli/dec/decode.h \
   third_party/brotli/dec/dictionary.h \
-  third_party/brotli/dec/dictionary.c \
   third_party/brotli/dec/huffman.c \
   third_party/brotli/dec/huffman.h \
   third_party/brotli/dec/port.h \
diff --git a/third_party/ots/README.chromium b/third_party/ots/README.chromium
index a520efdf..60dbf4c 100644
--- a/third_party/ots/README.chromium
+++ b/third_party/ots/README.chromium
@@ -1,6 +1,6 @@
 Name: OTS (OpenType Sanitizer)
 URL: https://github.com/khaledhosny/ots.git
-Version: 99a3b7ff8fb241e0f68a25a41726cc3421d1f9bf
+Version: 8ade3d16fbb0273e7f828191b4ad37b3819ce302
 Security Critical: yes
 License: BSD
 
diff --git a/third_party/ots/configure.ac b/third_party/ots/configure.ac
index 23ac941..9f67dec 100644
--- a/third_party/ots/configure.ac
+++ b/third_party/ots/configure.ac
@@ -1,5 +1,5 @@
 AC_INIT([OTS],
-        [5.0.0],
+        [5.0.1],
         [https://github.com/khaledhosny/ots/issues],
         [ots],
         [https://github.com/khaledhosny/ots])
diff --git a/third_party/ots/src/cmap.cc b/third_party/ots/src/cmap.cc
index 3ee201185..cbb5f3c3 100644
--- a/third_party/ots/src/cmap.cc
+++ b/third_party/ots/src/cmap.cc
@@ -282,7 +282,7 @@
   if (!subtable.ReadU32(&num_groups)) {
     return OTS_FAILURE_MSG("can't read number of format 12 subtable groups");
   }
-  if (num_groups == 0 || subtable.remaining() < num_groups * 12) {
+  if (num_groups == 0 || subtable.remaining() / 12 < num_groups) {
     return OTS_FAILURE_MSG("Bad format 12 subtable group count %d", num_groups);
   }
 
@@ -356,7 +356,7 @@
 
   // We limit the number of groups in the same way as in 3.10.12 tables. See
   // the comment there in
-  if (num_groups == 0 || subtable.remaining() < num_groups * 12) {
+  if (num_groups == 0 || subtable.remaining() / 12 < num_groups) {
     return OTS_FAILURE_MSG("Bad format 13 subtable group count %d", num_groups);
   }
 
@@ -464,7 +464,7 @@
       if (!subtable.ReadU32(&num_ranges)) {
         return OTS_FAILURE_MSG("Can't read number of ranges in record %d", i);
       }
-      if (num_ranges == 0 || subtable.remaining() < num_ranges * 4) {
+      if (num_ranges == 0 || subtable.remaining() / 4 < num_ranges) {
         return OTS_FAILURE_MSG("Bad number of ranges (%d) in record %d", num_ranges, i);
       }
 
@@ -498,7 +498,7 @@
       if (!subtable.ReadU32(&num_mappings)) {
         return OTS_FAILURE_MSG("Can't read number of mappings in variation selector record %d", i);
       }
-      if (num_mappings == 0 || subtable.remaining() < num_mappings * 5) {
+      if (num_mappings == 0 || subtable.remaining() / 5 < num_mappings) {
         return OTS_FAILURE_MSG("Bad number of mappings (%d) in variation selector record %d", num_mappings, i);
       }
 
diff --git a/third_party/ots/src/layout.cc b/third_party/ots/src/layout.cc
index e4f8070..1d87b53 100644
--- a/third_party/ots/src/layout.cc
+++ b/third_party/ots/src/layout.cc
@@ -95,9 +95,14 @@
 
   // The spec requires a script table for 'DFLT' tag must contain non-NULL
   // |offset_default_lang_sys| and |lang_sys_count| == 0
-  if (tag == kScriptTableTagDflt &&
-      (offset_default_lang_sys == 0 || lang_sys_count != 0)) {
-    return OTS_FAILURE_MSG("DFLT table doesn't satisfy the spec. for script tag %c%c%c%c", OTS_UNTAG(tag));
+  // https://www.microsoft.com/typography/otspec/chapter2.htm
+  if (tag == kScriptTableTagDflt) {
+    if (offset_default_lang_sys == 0) {
+      return OTS_FAILURE_MSG("DFLT script doesn't satisfy the spec. DefaultLangSys is NULL");
+    }
+    if (lang_sys_count != 0) {
+      return OTS_FAILURE_MSG("DFLT script doesn't satisfy the spec. LangSysCount is not zero: %d", lang_sys_count);
+    }
   }
 
   const unsigned lang_sys_record_end =
diff --git a/tools/android/loading/device_setup.py b/tools/android/loading/device_setup.py
index 24becb7..4d5d40b 100644
--- a/tools/android/loading/device_setup.py
+++ b/tools/android/loading/device_setup.py
@@ -17,17 +17,21 @@
 from pylib import constants
 from pylib import flag_changer
 
+import devtools_monitor
+
 DEVTOOLS_PORT = 9222
 DEVTOOLS_HOSTNAME = 'localhost'
+DEFAULT_CHROME_PACKAGE = 'chrome'
 
 @contextlib.contextmanager
-def FlagChanger(device, command_line_path, new_flags):
-  """Changes the flags in a context, restores them afterwards.
+def FlagReplacer(device, command_line_path, new_flags):
+  """Replaces chrome flags in a context, restores them afterwards.
 
   Args:
-    device: Device to target, from DeviceUtils.
+    device: Device to target, from DeviceUtils. Can be None, in which case this
+      context manager is a no-op.
     command_line_path: Full path to the command-line file.
-    new_flags: Flags to add.
+    new_flags: Flags to replace.
   """
   # If we're logging requests from a local desktop chrome instance there is no
   # device.
@@ -35,7 +39,7 @@
     yield
     return
   changer = flag_changer.FlagChanger(device, command_line_path)
-  changer.AddFlags(new_flags)
+  changer.ReplaceFlags(new_flags)
   try:
     yield
   finally:
@@ -63,28 +67,30 @@
   device.KillAll(package_info.package, quiet=True)
 
 
-def SetUpAndExecute(device, package, fn):
-  """Start logging process.
+@contextlib.contextmanager
+def DeviceConnection(device,
+                     package=DEFAULT_CHROME_PACKAGE,
+                     hostname=DEVTOOLS_HOSTNAME,
+                     port=DEVTOOLS_PORT):
+  """Context for starting recording on a device.
 
-  Sets up any device and tracing appropriately and then executes the core
-  logging function.
+  Sets up and restores any device and tracing appropriately
 
   Args:
-    device: Android device, or None for a local run.
+    device: Android device, or None for a local run (in which case chrome needs
+      to have been started with --remote-debugging-port=XXX).
     package: the key for chrome package info.
-    fn: the function to execute that launches chrome and performs the
-        appropriate instrumentation, see _Log*Internal().
 
   Returns:
-    As fn() returns.
+    A context manager type which evaluates to a DevToolsConnection.
   """
   package_info = constants.PACKAGE_INFO[package]
   command_line_path = '/data/local/chrome-command-line'
   new_flags = ['--enable-test-events',
-               '--remote-debugging-port=%d' % DEVTOOLS_PORT]
+               '--remote-debugging-port=%d' % port]
   if device:
     _SetUpDevice(device, package_info)
-  with FlagChanger(device, command_line_path, new_flags):
+  with FlagReplacer(device, command_line_path, new_flags):
     if device:
       start_intent = intent.Intent(
           package=package_info.package, activity=package_info.activity,
@@ -92,6 +98,25 @@
       device.StartActivity(start_intent, blocking=True)
       time.sleep(2)
     # If no device, we don't care about chrome startup so skip the about page.
-    with ForwardPort(device, 'tcp:%d' % DEVTOOLS_PORT,
+    with ForwardPort(device, 'tcp:%d' % port,
                      'localabstract:chrome_devtools_remote'):
-      return fn()
+      yield devtools_monitor.DevToolsConnection(hostname, port)
+
+
+def SetUpAndExecute(device, package, fn):
+  """Start logging process.
+
+  Wrapper for DeviceConnection for those functionally inclined.
+
+  Args:
+    device: Android device, or None for a local run.
+    package: the key for chrome package info.
+    fn: the function to execute that launches chrome and performs the
+        appropriate instrumentation. The function will receive a
+        DevToolsConnection as its sole parameter.
+
+  Returns:
+    As fn() returns.
+  """
+  with DeviceConnection(device, package) as connection:
+    return fn(connection)
diff --git a/tools/android/loading/devtools_monitor.py b/tools/android/loading/devtools_monitor.py
index fc652d2..5e8470ba 100644
--- a/tools/android/loading/devtools_monitor.py
+++ b/tools/android/loading/devtools_monitor.py
@@ -24,9 +24,62 @@
     logging.warning("DevToolsConnectionException: " + message)
 
 
+# Taken from telemetry.internal.backends.chrome_inspector.tracing_backend.
+# TODO(mattcary): combine this with the above and export?
+class _StreamReader(object):
+  def __init__(self, inspector, stream_handle):
+    self._inspector_websocket = inspector
+    self._handle = stream_handle
+    self._callback = None
+    self._data = None
+
+  def Read(self, callback):
+    # Do not allow the instance of this class to be reused, as
+    # we only read data sequentially at the moment, so a stream
+    # can only be read once.
+    assert not self._callback
+    self._data = []
+    self._callback = callback
+    self._ReadChunkFromStream()
+    # Queue one extra read ahead to avoid latency.
+    self._ReadChunkFromStream()
+
+  def _ReadChunkFromStream(self):
+    # Limit max block size to avoid fragmenting memory in sock.recv(),
+    # (see https://github.com/liris/websocket-client/issues/163 for details)
+    req = {'method': 'IO.read', 'params': {
+        'handle': self._handle, 'size': 32768}}
+    self._inspector_websocket.AsyncRequest(req, self._GotChunkFromStream)
+
+  def _GotChunkFromStream(self, response):
+    # Quietly discard responses from reads queued ahead after EOF.
+    if self._data is None:
+      return
+    if 'error' in response:
+      raise DevToolsConnectionException(
+          'Reading trace failed: %s' % response['error']['message'])
+    result = response['result']
+    self._data.append(result['data'])
+    if not result.get('eof', False):
+      self._ReadChunkFromStream()
+      return
+    req = {'method': 'IO.close', 'params': {'handle': self._handle}}
+    self._inspector_websocket.SendAndIgnoreResponse(req)
+    trace_string = ''.join(self._data)
+    self._data = None
+    self._callback(trace_string)
+
+
 class DevToolsConnection(object):
   """Handles the communication with a DevTools server.
   """
+  TRACING_DOMAIN = 'Tracing'
+  TRACING_END_METHOD = 'Tracing.end'
+  TRACING_DATA_METHOD = 'Tracing.dataCollected'
+  TRACING_DONE_EVENT = 'Tracing.tracingComplete'
+  TRACING_STREAM_EVENT = 'Tracing.tracingComplete'  # Same as TRACING_DONE.
+  TRACING_TIMEOUT = 300
+
   def __init__(self, hostname, port):
     """Initializes the connection with a DevTools server.
 
@@ -35,8 +88,11 @@
       port: port number.
     """
     self._ws = self._Connect(hostname, port)
-    self._listeners = {}
+    self._event_listeners = {}
+    self._domain_listeners = {}
     self._domains_to_enable = set()
+    self._tearing_down_tracing = False
+    self._set_up = False
     self._please_stop = False
 
   def RegisterListener(self, name, listener):
@@ -45,12 +101,16 @@
     Also takes care of enabling the relevant domain before starting monitoring.
 
     Args:
-      name: (str) Event the listener wants to listen to, e.g.
-            Network.requestWillBeSent.
+      name: (str) Domain or event the listener wants to listen to, e.g.
+            "Network.requestWillBeSent" or "Tracing".
       listener: (Listener) listener instance.
     """
-    domain = name[:name.index('.')]
-    self._listeners[name] = listener
+    if '.' in name:
+      domain = name[:name.index('.')]
+      self._event_listeners[name] = listener
+    else:
+      domain = name
+      self._domain_listeners[domain] = listener
     self._domains_to_enable.add(domain)
 
   def UnregisterListener(self, listener):
@@ -59,10 +119,14 @@
     Args:
       listener: (Listener) listener to unregister.
     """
-    keys = [k for (k, v) in self._listeners if v is listener]
+    keys = ([k for k, l in self._event_listeners if l is listener] +
+            [k for k, l in self._domain_listeners if l is listener])
     assert keys, "Removing non-existent listener"
     for key in keys:
-      del(self._listeners[key])
+      if key in self._event_listeners:
+        del(self._event_listeners[key])
+      if key in self._domain_listeners:
+        del(self._domain_listeners[key])
 
   def SyncRequest(self, method, params=None):
     """Issues a synchronous request to the DevTools server.
@@ -91,41 +155,103 @@
       request['params'] = params
     self._ws.SendAndIgnoreResponse(request)
 
+  def SyncRequestNoResponse(self, method, params=None):
+    """As SyncRequest, but asserts that no meaningful response was received.
+
+    Args:
+      method: (str) Method.
+      params: (dict) Optional parameters to the request.
+    """
+    result = self.SyncRequest(method, params)
+    if 'error' in result or ('result' in result and
+                             result['result']):
+      raise DevToolsConnectionException(
+          'Unexpected response for %s: %s' % (method, result))
+
   def SetUpMonitoring(self):
     for domain in self._domains_to_enable:
       self._ws.RegisterDomain(domain, self._OnDataReceived)
-      self.SyncRequest('%s.enable' % domain)
+      if domain != self.TRACING_DOMAIN:
+        self.SyncRequestNoResponse('%s.enable' % domain)
+        # Tracing setup must be done by the tracing track to control filtering
+        # and output.
+    self._tearing_down_tracing = False
+    self._set_up = True
 
   def StartMonitoring(self):
     """Starts monitoring.
 
     DevToolsConnection.SetUpMonitoring() has to be called first.
     """
-    while not self._please_stop:
-      try:
-        self._ws.DispatchNotifications()
-      except websocket.WebSocketTimeoutException:
-        break
-    if not self._please_stop:
-      logging.warning('Monitoring stopped on a timeout.')
+    assert self._set_up, 'DevToolsConnection.SetUpMonitoring not called.'
+    self._Dispatch()
     self._TearDownMonitoring()
 
   def StopMonitoring(self):
     """Stops the monitoring."""
     self._please_stop = True
 
+  def _Dispatch(self, kind='Monitoring', timeout=10):
+    self._please_stop = False
+    while not self._please_stop:
+      try:
+        self._ws.DispatchNotifications(timeout=timeout)
+      except websocket.WebSocketTimeoutException:
+        break
+    if not self._please_stop:
+      logging.warning('%s stopped on a timeout.' % kind)
+
   def _TearDownMonitoring(self):
+    if self.TRACING_DOMAIN in self._domains_to_enable:
+      logging.info('Fetching tracing')
+      self.SyncRequestNoResponse(self.TRACING_END_METHOD)
+      self._tearing_down_tracing = True
+      self._Dispatch(kind='Tracing', timeout=self.TRACING_TIMEOUT)
     for domain in self._domains_to_enable:
-      self.SyncRequest('%s.disable' % domain)
+      if domain != self.TRACING_DOMAIN:
+        self.SyncRequest('%s.disable' % domain)
       self._ws.UnregisterDomain(domain)
     self._domains_to_enable.clear()
-    self._listeners.clear()
+    self._domain_listeners.clear()
+    self._event_listeners.clear()
 
   def _OnDataReceived(self, msg):
-    method = msg.get('method', None)
-    if method not in self._listeners:
+    if 'method' not in msg:
+      raise DevToolsConnectionException('Malformed message: %s' % msg)
+    method = msg['method']
+    domain = method[:method.index('.')]
+
+    if self._tearing_down_tracing and method == self.TRACING_STREAM_EVENT:
+      stream_handle = msg.get('params', {}).get('stream')
+      if not stream_handle:
+        self._tearing_down_tracing = False
+        self.StopMonitoring()
+        # Fall through to regular dispatching.
+      else:
+        _StreamReader(self._ws, stream_handle).Read(self._TracingStreamDone)
+        # Skip regular dispatching.
+        return
+
+    if (method not in self._event_listeners and
+        domain not in self._domain_listeners):
       return
-    self._listeners[method].Handle(method, msg)
+    if method in self._event_listeners:
+      self._event_listeners[method].Handle(method, msg)
+    if domain in self._domain_listeners:
+      self._domain_listeners[domain].Handle(method, msg)
+    if self._tearing_down_tracing and method == self.TRACING_DONE_EVENT:
+      self._tearing_down_tracing = False
+      self.StopMonitoring()
+
+  def _TracingStreamDone(self, data):
+    tracing_events = json.loads(data)
+    for evt in tracing_events:
+      self._OnDataReceived({'method': self.TRACING_DATA_METHOD,
+                            'params': {'value': [evt]}})
+      if self._please_stop:
+        break
+    self._tearing_down_tracing = False
+    self.StopMonitoring()
 
   @classmethod
   def _GetWebSocketUrl(cls, hostname, port):
diff --git a/tools/android/loading/page_track.py b/tools/android/loading/page_track.py
new file mode 100644
index 0000000..bb289db
--- /dev/null
+++ b/tools/android/loading/page_track.py
@@ -0,0 +1,62 @@
+# Copyright 2016 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import devtools_monitor
+
+
+class PageTrack(devtools_monitor.Track):
+  """Records the events from the page track."""
+  _METHODS = ('Page.frameStartedLoading', 'Page.frameStoppedLoading',
+              'Page.frameAttached')
+  def __init__(self, connection):
+    super(PageTrack, self).__init__(connection)
+    self._connection = connection
+    self._events = []
+    self._pending_frames = set()
+    self._known_frames = set()
+    self._main_frame_id = None
+    if self._connection:
+      for method in PageTrack._METHODS:
+        self._connection.RegisterListener(method, self)
+
+  def Handle(self, method, msg):
+    assert method in PageTrack._METHODS
+    params = msg['params']
+    frame_id = params['frameId']
+    should_stop = False
+    event = {'method': method, 'frame_id': frame_id}
+    if method == 'Page.frameStartedLoading':
+      if self._main_frame_id is None:
+        self._main_frame_id = params['frameId']
+      self._pending_frames.add(frame_id)
+      self._known_frames.add(frame_id)
+    elif method == 'Page.frameStoppedLoading':
+      assert frame_id in self._pending_frames
+      self._pending_frames.remove(frame_id)
+      if frame_id == self._main_frame_id:
+        should_stop = True
+    elif method == 'Page.frameAttached':
+      self._known_frames.add(frame_id)
+      parent_frame = params['parentFrameId']
+      assert parent_frame in self._known_frames
+      event['parent_frame_id'] = parent_frame
+    self._events.append(event)
+    if should_stop and self._connection:
+      self._connection.StopMonitoring()
+
+  def GetEvents(self):
+    #TODO(lizeb): Add more checks here (child frame stops loading before parent,
+    #for instance).
+    return self._events
+
+  def ToJsonDict(self):
+    return {'events': [event for event in self._events]}
+
+  @classmethod
+  def FromJsonDict(cls, json_dict):
+    assert 'events' in json_dict
+    result = PageTrack(None)
+    events = [event for event in json_dict['events']]
+    result._events = events
+    return result
diff --git a/tools/android/loading/page_track_unittest.py b/tools/android/loading/page_track_unittest.py
new file mode 100644
index 0000000..6757a01
--- /dev/null
+++ b/tools/android/loading/page_track_unittest.py
@@ -0,0 +1,58 @@
+# Copyright 2016 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import unittest
+
+import devtools_monitor
+from page_track import PageTrack
+
+class MockDevToolsConnection(object):
+  def __init__(self):
+    self.stop_has_been_called = False
+
+  def RegisterListener(self, name, listener):
+    pass
+
+  def StopMonitoring(self):
+    self.stop_has_been_called = True
+
+
+class PageTrackTest(unittest.TestCase):
+  _EVENTS = [{'method': 'Page.frameStartedLoading',
+              'params': {'frameId': '1234.1'}},
+             {'method': 'Page.frameAttached',
+              'params': {'frameId': '1234.12', 'parentFrameId': '1234.1'}},
+             {'method': 'Page.frameStartedLoading',
+              'params': {'frameId': '1234.12'}},
+             {'method': 'Page.frameStoppedLoading',
+              'params': {'frameId': '1234.12'}},
+             {'method': 'Page.frameStoppedLoading',
+              'params': {'frameId': '1234.1'}}]
+  def testAsksMonitoringToStop(self):
+    devtools_connection = MockDevToolsConnection()
+    page_track = PageTrack(devtools_connection)
+    for msg in PageTrackTest._EVENTS[:-1]:
+      page_track.Handle(msg['method'], msg)
+      self.assertFalse(devtools_connection.stop_has_been_called)
+    msg = PageTrackTest._EVENTS[-1]
+    page_track.Handle(msg['method'], msg)
+    self.assertTrue(devtools_connection.stop_has_been_called)
+
+  def testUnknownParent(self):
+    page_track = PageTrack(None)
+    msg = {'method': 'Page.frameAttached',
+           'params': {'frameId': '1234.12', 'parentFrameId': '1234.1'}}
+    with self.assertRaises(AssertionError):
+      page_track.Handle(msg['method'], msg)
+
+  def testStopsLoadingUnknownFrame(self):
+    page_track = PageTrack(None)
+    msg = {'method': 'Page.frameStoppedLoading',
+           'params': {'frameId': '1234.12'}}
+    with self.assertRaises(AssertionError):
+      page_track.Handle(msg['method'], msg)
+
+
+if __name__ == '__main__':
+  unittest.main()
diff --git a/tools/android/loading/request_track.py b/tools/android/loading/request_track.py
index de3fd115..08e15880 100644
--- a/tools/android/loading/request_track.py
+++ b/tools/android/loading/request_track.py
@@ -104,6 +104,17 @@
       setattr(result, k, v)
     return result
 
+  def GetContentType(self):
+    """Returns the content type, or None."""
+    content_type = self.response_headers.get('Content-Type', None)
+    if not content_type or ';' not in content_type:
+      return content_type
+    else:
+      return content_type[:content_type.index(';')]
+
+  def IsDataRequest(self):
+    return self.protocol == 'data'
+
   # For testing.
   def __eq__(self, o):
     return self.__dict__ == o.__dict__
diff --git a/tools/android/loading/request_track_unittest.py b/tools/android/loading/request_track_unittest.py
index 459e2de..1e9403b2 100644
--- a/tools/android/loading/request_track_unittest.py
+++ b/tools/android/loading/request_track_unittest.py
@@ -8,6 +8,17 @@
 from request_track import (Request, RequestTrack, _TimingFromDict)
 
 
+class RequestTestCase(unittest.TestCase):
+  def testContentType(self):
+    r = Request()
+    r.response_headers = {}
+    self.assertEquals(None, r.GetContentType())
+    r.response_headers = {'Content-Type': 'application/javascript'}
+    self.assertEquals('application/javascript', r.GetContentType())
+    r.response_headers = {'Content-Type': 'application/javascript;bla'}
+    self.assertEquals('application/javascript', r.GetContentType())
+
+
 class RequestTrackTestCase(unittest.TestCase):
   _REQUEST_WILL_BE_SENT = {
       'method': 'Network.requestWillBeSent',
diff --git a/tools/android/loading/trace_recorder.py b/tools/android/loading/trace_recorder.py
index 6e638c4..0b96225 100755
--- a/tools/android/loading/trace_recorder.py
+++ b/tools/android/loading/trace_recorder.py
@@ -19,46 +19,7 @@
 
 import device_setup
 import devtools_monitor
-
-
-class PageTrack(devtools_monitor.Track):
-  """Records the events from the page track."""
-  def __init__(self, connection):
-    super(PageTrack, self).__init__()
-    self._connection = connection
-    self._events = []
-    self._main_frame_id = None
-    if self._connection:
-      self._connection.RegisterListener('Page.frameStartedLoading', self)
-      self._connection.RegisterListener('Page.frameStoppedLoading', self)
-
-  def Handle(self, method, msg):
-    params = msg['params']
-    frame_id = params['frameId']
-    should_stop = False
-    if method == 'Page.frameStartedLoading' and self._main_frame_id is None:
-      self._main_frame_id = params['frameId']
-    elif (method == 'Page.frameStoppedLoading'
-          and params['frameId'] == self._main_frame_id):
-      should_stop = True
-    self._events.append((method, frame_id))
-    if should_stop:
-      self._connection.StopMonitoring()
-
-  def GetEvents(self):
-    return self._events
-
-  def ToJsonDict(self):
-    return {'events': [event for event in self._events]}
-
-  @classmethod
-  def FromJsonDict(cls, json_dict):
-    assert 'events' in json_dict
-    result = PageTrack(None)
-    events = [event for event in json_dict['events']]
-    result._events = events
-    return result
-
+import page_track
 
 class AndroidTraceRecorder(object):
   """Records a loading trace."""
@@ -67,11 +28,9 @@
     self.devtools_connection = None
     self.page_track = None
 
-  def Go(self):
-    self.devtools_connection = devtools_monitor.DevToolsConnection(
-        device_setup.DEVTOOLS_HOSTNAME, device_setup.DEVTOOLS_PORT)
-    self.page_track = PageTrack(self.devtools_connection)
-
+  def Go(self, connection):
+    self.devtools_connection = connection
+    self.page_track = page_track.PageTrack(self.devtools_connection)
     self.devtools_connection.SetUpMonitoring()
     self.devtools_connection.SendAndIgnoreResponse(
         'Page.navigate', {'url': self.url})
diff --git a/tools/android/loading/trace_to_chrome_trace.py b/tools/android/loading/trace_to_chrome_trace.py
new file mode 100755
index 0000000..998614f3
--- /dev/null
+++ b/tools/android/loading/trace_to_chrome_trace.py
@@ -0,0 +1,23 @@
+#! /usr/bin/python
+# 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.
+
+"""Convert trace output for Chrome.
+
+Take the tracing track output from tracing_driver.py to a zip'd json that can be
+loading by chrome devtools tracing.
+"""
+
+import argparse
+import gzip
+import json
+
+if __name__ == '__main__':
+  parser = argparse.ArgumentParser()
+  parser.add_argument('input')
+  parser.add_argument('output')
+  args = parser.parse_args()
+  with gzip.GzipFile(args.output, 'w') as output_f, file(args.input) as input_f:
+    events = json.load(input_f)
+    json.dump({'traceEvents': events, 'metadata': {}}, output_f)
diff --git a/tools/android/loading/tracing.py b/tools/android/loading/tracing.py
new file mode 100644
index 0000000..83ad38c1
--- /dev/null
+++ b/tools/android/loading/tracing.py
@@ -0,0 +1,38 @@
+# Copyright 2016 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Monitor tracing events on chrome via chrome remote debugging."""
+
+import devtools_monitor
+
+class TracingTrack(devtools_monitor.Track):
+  def __init__(self, connection, categories=None, fetch_stream=False):
+    """Initialize this TracingTrack.
+
+    Args:
+      connection: a DevToolsConnection.
+      categories: None, or a string, or list of strings, of tracing categories
+        to filter.
+
+      fetch_stream: if true, use a websocket stream to fetch tracing data rather
+        than dataCollected events. It appears based on very limited testing that
+        a stream is slower than the default reporting as dataCollected events.
+    """
+    super(TracingTrack, self).__init__(connection)
+    connection.RegisterListener('Tracing.dataCollected', self)
+    params = {}
+    if categories:
+      params['categories'] = (categories if type(categories) is str
+                              else ','.join(categories))
+    if fetch_stream:
+      params['transferMode'] = 'ReturnAsStream'
+
+    connection.SyncRequestNoResponse('Tracing.start', params)
+    self._events = []
+
+  def Handle(self, method, event):
+    self._events.append(event)
+
+  def GetEvents(self):
+    return self._events
diff --git a/tools/android/loading/tracing_driver.py b/tools/android/loading/tracing_driver.py
new file mode 100755
index 0000000..c62e870
--- /dev/null
+++ b/tools/android/loading/tracing_driver.py
@@ -0,0 +1,49 @@
+#! /usr/bin/python
+# Copyright 2016 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Drive TracingConnection"""
+
+import argparse
+import json
+import logging
+import os.path
+import sys
+
+_SRC_DIR = os.path.abspath(os.path.join(
+    os.path.dirname(__file__), '..', '..', '..'))
+
+sys.path.append(os.path.join(_SRC_DIR, 'third_party', 'catapult', 'devil'))
+from devil.android import device_utils
+
+sys.path.append(os.path.join(_SRC_DIR, 'build', 'android'))
+import device_setup
+import page_track
+import tracing
+
+
+def main():
+  logging.basicConfig(level=logging.INFO)
+  parser = argparse.ArgumentParser()
+  parser.add_argument('--url', required=True)
+  parser.add_argument('--output', required=True)
+  args = parser.parse_args()
+  url = args.url
+  if not url.startswith('http'):
+    url = 'http://' + url
+  device = device_utils.DeviceUtils.HealthyDevices()[0]
+  with file(args.output, 'w') as output, \
+       file(args.output + '.page', 'w') as page_output, \
+       device_setup.DeviceConnection(device) as connection:
+    track = tracing.TracingTrack(connection, fetch_stream=False)
+    page = page_track.PageTrack(connection)
+    connection.SetUpMonitoring()
+    connection.SendAndIgnoreResponse('Page.navigate', {'url': url})
+    connection.StartMonitoring()
+    json.dump(page.GetEvents(), page_output, sort_keys=True, indent=2)
+    json.dump(track.GetEvents(), output, sort_keys=True, indent=2)
+
+
+if __name__ == '__main__':
+  main()
diff --git a/tools/clang/scripts/update.py b/tools/clang/scripts/update.py
index ef6ca07..b57259f 100755
--- a/tools/clang/scripts/update.py
+++ b/tools/clang/scripts/update.py
@@ -26,7 +26,7 @@
 # Do NOT CHANGE this if you don't know what you're doing -- see
 # https://code.google.com/p/chromium/wiki/UpdatingClang
 # Reverting problematic clang rolls is safe, though.
-CLANG_REVISION = '255169'
+CLANG_REVISION = '257953'
 
 use_head_revision = 'LLVM_FORCE_HEAD_REVISION' in os.environ
 if use_head_revision:
@@ -65,7 +65,7 @@
 STAMP_FILE = os.path.normpath(
     os.path.join(LLVM_DIR, '..', 'llvm-build', 'cr_build_revision'))
 BINUTILS_DIR = os.path.join(THIRD_PARTY_DIR, 'binutils')
-VERSION = '3.8.0'
+VERSION = '3.9.0'
 ANDROID_NDK_DIR = os.path.join(
     CHROMIUM_DIR, 'third_party', 'android_tools', 'ndk')
 
@@ -597,6 +597,8 @@
   elif sys.platform.startswith('linux'):
     RunCommand(['strip', os.path.join(LLVM_BUILD_DIR, 'bin', 'clang')])
 
+  # TODO(thakis): Check that `clang --version` matches VERSION.
+
   # Do an out-of-tree build of compiler-rt.
   # On Windows, this is used to get the 32-bit ASan run-time.
   # TODO(hans): Remove once the regular build above produces this.
@@ -787,11 +789,6 @@
       print 'Skipping Clang update (make_clang_dir= was set in GYP_DEFINES).'
       return 0
 
-  if use_head_revision:
-    # TODO(hans): Remove after the next roll.
-    global VERSION
-    VERSION = '3.9.0'
-
   global CLANG_REVISION, PACKAGE_VERSION
   if args.print_revision:
     if use_head_revision:
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index 45c6a84..999559c 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -32763,11 +32763,16 @@
   </summary>
 </histogram>
 
-<histogram name="PasswordManager.SyncCredentialFiltered" enum="Boolean">
+<histogram name="PasswordManager.SyncCredentialFiltered"
+    enum="CredentialFilteredType">
   <owner>gcasto@chromium.org</owner>
   <owner>vabr@chromium.org</owner>
   <summary>
-    If the sync credential was removed from autofill consideration.
+    This histogram is reported for those forms on accounts.google.com, on which
+    Chrome is forced by Finch/flags during autofilling to remove sync
+    credentials from password store results. It reports true if sync credentials
+    were indeed removed from the store results, and false if there were no sync
+    credentials in the results to begin with.
   </summary>
 </histogram>
 
@@ -39207,6 +39212,28 @@
   </summary>
 </histogram>
 
+<histogram name="Renderer4.MainThreadGestureScrollReason"
+    enum="MainThreadScrollingReason">
+  <owner>tdresser@chromium.org</owner>
+  <summary>
+    Ideally we'd always scroll on the impl thread, but there are a variety of
+    situations where we need to scroll on main. We should try to drive these
+    down. For every gesture, we record whether or not the scroll occurred on the
+    main thread, and if it did, what the reason was.
+  </summary>
+</histogram>
+
+<histogram name="Renderer4.MainThreadWheelScrollReason"
+    enum="MainThreadScrollingReason">
+  <owner>tdresser@chromium.org</owner>
+  <summary>
+    Ideally we'd always scroll on the impl thread, but there are a variety of
+    situations where we need to scroll on main. We should try to drive these
+    down. For every wheel tick, we record whether or not the the scroll occurred
+    on the main thread, and if it did, what the reason was.
+  </summary>
+</histogram>
+
 <histogram name="Renderer4.pixelCountCulled_Draw" units="NormalizedPixels">
   <owner>wiltzius@chromium.org</owner>
   <summary>
@@ -51188,8 +51215,8 @@
 </histogram>
 
 <histogram name="TryScroll.SlowScroll" enum="ScrollThread">
-  <owner>Please list the metric's owners. Add more owner tags as needed.</owner>
-  <summary>Whether the scroll is executed on main thread.</summary>
+  <owner>tdresser@chromium.org</owner>
+  <summary>Whether a scroll is executed on main thread.</summary>
 </histogram>
 
 <histogram name="UMA.ActualLogUploadInterval" units="minutes">
@@ -59225,6 +59252,9 @@
   <int value="7011" label="SBOX_FATAL_MITIGATION"/>
   <int value="7012" label="SBOX_FATAL_MEMORY_EXCEEDED"/>
   <int value="7013" label="SBOX_FATAL_WARMUP"/>
+  <int value="36862" label="Crashpad_FailedToCaptureProcess"/>
+  <int value="36863" label="Crashpad_HandlerDidNotRespond"/>
+  <int value="85436397" label="Crashpad_SimulatedCrash"/>
   <int value="529697949" label="CPP_EH_EXCEPTION"/>
   <int value="533692099" label="STATUS_GUARD_PAGE_VIOLATION"/>
   <int value="1073740791" label="STATUS_STACK_BUFFER_OVERRUN"/>
@@ -59258,6 +59288,11 @@
   <int value="2147483646" label="STATUS_DATATYPE_MISALIGNMENT"/>
 </enum>
 
+<enum name="CredentialFilteredType" type="int">
+  <int value="0" label="No sync credentials present"/>
+  <int value="1" label="Sync credentials were removed"/>
+</enum>
+
 <enum name="CrosBeamformingDeviceState" type="int">
   <int value="0" label="Default enabled"/>
   <int value="1" label="User enabled"/>
@@ -69955,6 +69990,22 @@
   <int value="1" label="cache-control: no-store"/>
 </enum>
 
+<enum name="MainThreadScrollingReason" type="int">
+  <int value="0" label="Not scrolling on main"/>
+  <int value="1" label="Background attachment fixed"/>
+  <int value="2" label="Non layer viewport constrained"/>
+  <int value="3" label="Threaded scrolling disabled"/>
+  <int value="4" label="Scrollbar scrolling"/>
+  <int value="5" label="Page overlay"/>
+  <int value="6" label="Non-fast scrollable region"/>
+  <int value="7" label="Event handlers"/>
+  <int value="8" label="Failed hit test"/>
+  <int value="9" label="No scrolling layer"/>
+  <int value="10" label="Not scrollable"/>
+  <int value="11" label="Continuing main thread scroll"/>
+  <int value="12" label="Non-invertible transform"/>
+</enum>
+
 <enum name="MakeChromeDefaultResult" type="int">
   <int value="0" label="Chrome made default"/>
   <int value="1" label="Dialog closed without explicit choice"/>
@@ -80701,6 +80752,8 @@
   <int value="-1073740777"
       label="0xC0000417 - STATUS_INVALID_CRUNTIME_PARAMETER"/>
   <int value="-805306369" label="0xCFFFFFFF - Hung browser killed."/>
+  <int value="-36863" label="0xFFFF7001 - Crashpad kCrashExitCodeNoDump."/>
+  <int value="-36862" label="0xFFFF7002 - Crashpad kFailedTerminationCode."/>
   <int value="0" label="content::RESULT_CODE_NORMAL_EXIT"/>
   <int value="1" label="content::RESULT_CODE_KILLED"/>
   <int value="2" label="content::RESULT_CODE_HUNG"/>
@@ -80733,6 +80786,7 @@
   <int value="29" label="chrome::RESULT_CODE_ACTION_DISALLOWED_BY_POLICY"/>
   <int value="30" label="chrome::RESULT_CODE_INVALID_SANDBOX_STATE"/>
   <int value="259" label="0x103 - STILL_ACTIVE."/>
+  <int value="85436397" label="0x517a7ed - Crashpad simulated exception"/>
   <int value="1073807364" label="0x40010004 - DBG_TERMINATE_PROCESS"/>
 </enum>
 
diff --git a/tools/valgrind/drmemory/suppressions_full.txt b/tools/valgrind/drmemory/suppressions_full.txt
index eae9dcb..fd1d3a5 100644
--- a/tools/valgrind/drmemory/suppressions_full.txt
+++ b/tools/valgrind/drmemory/suppressions_full.txt
@@ -2103,8 +2103,6 @@
 content.dll!content::RenderWidgetHostImpl::SetIsLoading
 content.dll!content::RenderFrameHostManager::SetIsLoading
 content.dll!content::WebContentsImpl::SetIsLoading
-content.dll!content::WebContentsImpl::DidStopLoading
-content.dll!content::FrameTreeNode::DidStopLoading
 
 HANDLE LEAK
 name=bug_571554_a
diff --git a/tools/valgrind/memcheck/suppressions.txt b/tools/valgrind/memcheck/suppressions.txt
index 73d9fa0e..4deeac34 100644
--- a/tools/valgrind/memcheck/suppressions.txt
+++ b/tools/valgrind/memcheck/suppressions.txt
@@ -935,7 +935,7 @@
    fun:_ZN14GpuProcessHost4InitEv
 }
 {
-   bug_67261
+   bug_67261a
    Memcheck:Leak
    fun:_Znw*
    ...
@@ -944,6 +944,16 @@
    fun:_ZN8appcache16AppCacheDatabase22PrepareCachedStatementERKN3sql11StatementIDEPKcPNS1_9StatementE
 }
 {
+   bug_67261b
+   Memcheck:Leak
+   fun:_Znw*
+   fun:_ZN3sql10Connection18GetUniqueStatementEPKc
+   fun:_ZN3sql10Connection18GetCachedStatementERKNS_11StatementIDEPKc
+   fun:_ZN3sql9MetaTable19PrepareGetStatementEPNS_9StatementEPKc
+   fun:_ZN3sql9MetaTable8GetValueEPKcPi
+   fun:_ZN7storage13QuotaDatabase28IsOriginDatabaseBootstrappedEv
+}
+{
    bug_67553
    Memcheck:Leak
    fun:_Znw*
diff --git a/ui/aura/BUILD.gn b/ui/aura/BUILD.gn
index 6f112e67..dfe5349 100644
--- a/ui/aura/BUILD.gn
+++ b/ui/aura/BUILD.gn
@@ -68,8 +68,6 @@
     "layout_manager.h",
     "mus/mus_util.cc",
     "mus/mus_util.h",
-    "remote_window_tree_host_win.cc",
-    "remote_window_tree_host_win.h",
     "scoped_window_targeter.cc",
     "scoped_window_targeter.h",
     "window.cc",
diff --git a/ui/aura/aura.gyp b/ui/aura/aura.gyp
index 12230e2..e338d3a 100644
--- a/ui/aura/aura.gyp
+++ b/ui/aura/aura.gyp
@@ -88,8 +88,6 @@
         'input_state_lookup_win.h',
         'layout_manager.cc',
         'layout_manager.h',
-        'remote_window_tree_host_win.cc',
-        'remote_window_tree_host_win.h',
         'scoped_window_targeter.cc',
         'scoped_window_targeter.h',
         'window.cc',
diff --git a/ui/aura/remote_window_tree_host_win.cc b/ui/aura/remote_window_tree_host_win.cc
deleted file mode 100644
index a303d98..0000000
--- a/ui/aura/remote_window_tree_host_win.cc
+++ /dev/null
@@ -1,522 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/aura/remote_window_tree_host_win.h"
-
-#include <windows.h>
-#include <stddef.h>
-
-#include <algorithm>
-
-#include "base/message_loop/message_loop.h"
-#include "ipc/ipc_message.h"
-#include "ipc/ipc_sender.h"
-#include "ui/aura/client/cursor_client.h"
-#include "ui/aura/window_event_dispatcher.h"
-#include "ui/aura/window_property.h"
-#include "ui/base/cursor/cursor_loader_win.h"
-#include "ui/base/ime/composition_text.h"
-#include "ui/base/ime/input_method.h"
-#include "ui/base/ime/remote_input_method_win.h"
-#include "ui/base/ime/text_input_client.h"
-#include "ui/base/view_prop.h"
-#include "ui/events/event_utils.h"
-#include "ui/events/keycodes/keyboard_code_conversion_win.h"
-#include "ui/gfx/geometry/insets.h"
-#include "ui/gfx/win/dpi.h"
-#include "ui/metro_viewer/metro_viewer_messages.h"
-
-namespace aura {
-
-namespace {
-
-const char* kWindowTreeHostWinKey = "__AURA_REMOTE_WINDOW_TREE_HOST_WIN__";
-
-// Sets the keystate for the virtual key passed in to down or up.
-void SetKeyState(uint8_t* key_states,
-                 bool key_down,
-                 uint32_t virtual_key_code) {
-  DCHECK(key_states);
-
-  if (key_down)
-    key_states[virtual_key_code] |= 0x80;
-  else
-    key_states[virtual_key_code] &= 0x7F;
-}
-
-// Sets the keyboard states for the Shift/Control/Alt/Caps lock keys.
-void SetVirtualKeyStates(uint32_t flags) {
-  uint8_t keyboard_state[256] = {0};
-  ::GetKeyboardState(keyboard_state);
-
-  SetKeyState(keyboard_state, !!(flags & ui::EF_SHIFT_DOWN), VK_SHIFT);
-  SetKeyState(keyboard_state, !!(flags & ui::EF_CONTROL_DOWN), VK_CONTROL);
-  SetKeyState(keyboard_state, !!(flags & ui::EF_ALT_DOWN), VK_MENU);
-  SetKeyState(keyboard_state, !!(flags & ui::EF_CAPS_LOCK_ON), VK_CAPITAL);
-  SetKeyState(keyboard_state, !!(flags & ui::EF_LEFT_MOUSE_BUTTON), VK_LBUTTON);
-  SetKeyState(keyboard_state, !!(flags & ui::EF_RIGHT_MOUSE_BUTTON),
-              VK_RBUTTON);
-  SetKeyState(keyboard_state, !!(flags & ui::EF_MIDDLE_MOUSE_BUTTON),
-              VK_MBUTTON);
-
-  ::SetKeyboardState(keyboard_state);
-}
-
-void FillCompositionText(
-    const base::string16& text,
-    int32_t selection_start,
-    int32_t selection_end,
-    const std::vector<metro_viewer::UnderlineInfo>& underlines,
-    ui::CompositionText* composition_text) {
-  composition_text->Clear();
-  composition_text->text = text;
-  composition_text->selection.set_start(selection_start);
-  composition_text->selection.set_end(selection_end);
-  composition_text->underlines.resize(underlines.size());
-  for (size_t i = 0; i < underlines.size(); ++i) {
-    composition_text->underlines[i].start_offset = underlines[i].start_offset;
-    composition_text->underlines[i].end_offset = underlines[i].end_offset;
-    composition_text->underlines[i].color = SK_ColorBLACK;
-    composition_text->underlines[i].thick = underlines[i].thick;
-    composition_text->underlines[i].background_color = SK_ColorTRANSPARENT;
-  }
-}
-
-}  // namespace
-
-RemoteWindowTreeHostWin* g_instance = NULL;
-
-// static
-RemoteWindowTreeHostWin* RemoteWindowTreeHostWin::Instance() {
-  return g_instance;
-}
-
-RemoteWindowTreeHostWin::RemoteWindowTreeHostWin()
-    : remote_window_(NULL),
-      host_(NULL),
-      ignore_mouse_moves_until_set_cursor_ack_(0),
-      event_flags_(0),
-      window_size_(GetSystemMetrics(SM_CXSCREEN),
-                   GetSystemMetrics(SM_CYSCREEN)) {
-  CHECK(!g_instance);
-  g_instance = this;
-  prop_.reset(new ui::ViewProp(NULL, kWindowTreeHostWinKey, this));
-  CreateCompositor();
-  OnAcceleratedWidgetAvailable();
-}
-
-RemoteWindowTreeHostWin::~RemoteWindowTreeHostWin() {
-  DestroyCompositor();
-  DestroyDispatcher();
-  DCHECK_EQ(g_instance, this);
-  g_instance = NULL;
-}
-
-// static
-bool RemoteWindowTreeHostWin::IsValid() {
-  return Instance()->remote_window_ != NULL;
-}
-
-void RemoteWindowTreeHostWin::SetRemoteWindowHandle(HWND remote_window) {
-  remote_window_ = remote_window;
-}
-
-void RemoteWindowTreeHostWin::Connected(IPC::Sender* host) {
-  CHECK(host_ == NULL);
-  DCHECK(remote_window_);
-  host_ = host;
-  // Recreate the compositor for the target surface represented by the
-  // remote_window HWND.
-  CreateCompositor();
-  OnAcceleratedWidgetAvailable();
-  InitCompositor();
-}
-
-void RemoteWindowTreeHostWin::Disconnected() {
-  // Don't CHECK here, Disconnected is called on a channel error which can
-  // happen before we're successfully Connected.
-  if (!host_)
-    return;
-  ui::RemoteInputMethodPrivateWin* remote_input_method_private =
-      GetRemoteInputMethodPrivate();
-  if (remote_input_method_private)
-    remote_input_method_private->SetRemoteDelegate(NULL);
-  host_ = NULL;
-  remote_window_ = NULL;
-}
-
-bool RemoteWindowTreeHostWin::OnMessageReceived(const IPC::Message& message) {
-  bool handled = true;
-  IPC_BEGIN_MESSAGE_MAP(RemoteWindowTreeHostWin, message)
-    IPC_MESSAGE_HANDLER(MetroViewerHostMsg_MouseMoved, OnMouseMoved)
-    IPC_MESSAGE_HANDLER(MetroViewerHostMsg_MouseButton, OnMouseButton)
-    IPC_MESSAGE_HANDLER(MetroViewerHostMsg_KeyDown, OnKeyDown)
-    IPC_MESSAGE_HANDLER(MetroViewerHostMsg_KeyUp, OnKeyUp)
-    IPC_MESSAGE_HANDLER(MetroViewerHostMsg_Character, OnChar)
-    IPC_MESSAGE_HANDLER(MetroViewerHostMsg_WindowActivated,
-                        OnWindowActivated)
-    IPC_MESSAGE_HANDLER(MetroViewerHostMsg_EdgeGesture, OnEdgeGesture)
-    IPC_MESSAGE_HANDLER(MetroViewerHostMsg_TouchDown,
-                        OnTouchDown)
-    IPC_MESSAGE_HANDLER(MetroViewerHostMsg_TouchUp,
-                        OnTouchUp)
-    IPC_MESSAGE_HANDLER(MetroViewerHostMsg_TouchMoved,
-                        OnTouchMoved)
-    IPC_MESSAGE_HANDLER(MetroViewerHostMsg_SetCursorPosAck,
-                        OnSetCursorPosAck)
-    IPC_MESSAGE_HANDLER(MetroViewerHostMsg_ImeCandidatePopupChanged,
-                        OnImeCandidatePopupChanged)
-    IPC_MESSAGE_HANDLER(MetroViewerHostMsg_ImeCompositionChanged,
-                        OnImeCompositionChanged)
-    IPC_MESSAGE_HANDLER(MetroViewerHostMsg_ImeTextCommitted,
-                        OnImeTextCommitted)
-    IPC_MESSAGE_HANDLER(MetroViewerHostMsg_ImeInputSourceChanged,
-                        OnImeInputSourceChanged)
-    IPC_MESSAGE_UNHANDLED(handled = false)
-  IPC_END_MESSAGE_MAP()
-  return handled;
-}
-
-void RemoteWindowTreeHostWin::HandleOpenURLOnDesktop(
-    const base::FilePath& shortcut,
-    const base::string16& url) {
-  if (!host_)
-    return;
-  host_->Send(new MetroViewerHostMsg_OpenURLOnDesktop(shortcut, url));
-}
-
-void RemoteWindowTreeHostWin::HandleWindowSizeChanged(uint32_t width,
-                                                      uint32_t height) {
-  SetBounds(gfx::Rect(0, 0, width, height));
-}
-
-bool RemoteWindowTreeHostWin::IsForegroundWindow() {
-  return ::GetForegroundWindow() == remote_window_;
-}
-
-Window* RemoteWindowTreeHostWin::GetAshWindow() {
-  return window();
-}
-
-ui::EventSource* RemoteWindowTreeHostWin::GetEventSource() {
-  return this;
-}
-
-gfx::AcceleratedWidget RemoteWindowTreeHostWin::GetAcceleratedWidget() {
-  if (remote_window_)
-    return remote_window_;
-  // Getting here should only happen for ash_unittests.exe and related code.
-  return ::GetDesktopWindow();
-}
-
-void RemoteWindowTreeHostWin::ShowImpl() {
-  ui::RemoteInputMethodPrivateWin* remote_input_method_private =
-      GetRemoteInputMethodPrivate();
-  if (remote_input_method_private)
-    remote_input_method_private->SetRemoteDelegate(this);
-}
-
-void RemoteWindowTreeHostWin::HideImpl() {
-  NOTIMPLEMENTED();
-}
-
-gfx::Rect RemoteWindowTreeHostWin::GetBounds() const {
-  return gfx::Rect(window_size_);
-}
-
-void RemoteWindowTreeHostWin::SetBounds(const gfx::Rect& bounds) {
-  window_size_ = bounds.size();
-  OnHostResized(bounds.size());
-}
-
-gfx::Point RemoteWindowTreeHostWin::GetLocationOnNativeScreen() const {
-  return gfx::Point(0, 0);
-}
-
-void RemoteWindowTreeHostWin::SetCapture() {
-}
-
-void RemoteWindowTreeHostWin::ReleaseCapture() {
-}
-
-void RemoteWindowTreeHostWin::SetCursorNative(gfx::NativeCursor native_cursor) {
-  if (!host_)
-    return;
-  host_->Send(
-      new MetroViewerHostMsg_SetCursor(uint64_t(native_cursor.platform())));
-}
-
-void RemoteWindowTreeHostWin::MoveCursorToNative(const gfx::Point& location) {
-  VLOG(1) << "In MoveCursorTo: " << location.x() << ", " << location.y();
-  if (!host_)
-    return;
-
-  // This function can be called in cases like when the mouse cursor is
-  // restricted within a viewport (For e.g. LockCursor) which assumes that
-  // subsequent mouse moves would be received starting with the new cursor
-  // coordinates. This is a challenge for Windows ASH for the reasons
-  // outlined below.
-  // Other cases which don't expect this behavior should continue to work
-  // without issues.
-
-  // The mouse events are received by the viewer process and sent to the
-  // browser. If we invoke the SetCursor API here we continue to receive
-  // mouse messages from the viewer which were posted before the SetCursor
-  // API executes which messes up the state in the browser. To workaround
-  // this we invoke the SetCursor API in the viewer process and ignore
-  // mouse messages until we received an ACK from the viewer indicating that
-  // the SetCursor operation completed.
-  ignore_mouse_moves_until_set_cursor_ack_++;
-  VLOG(1) << "In MoveCursorTo. Sending IPC";
-  host_->Send(new MetroViewerHostMsg_SetCursorPos(location.x(), location.y()));
-}
-
-void RemoteWindowTreeHostWin::OnCursorVisibilityChangedNative(bool show) {
-  NOTIMPLEMENTED();
-}
-
-void RemoteWindowTreeHostWin::CancelComposition() {
-  if (!host_)
-    return;
-  host_->Send(new MetroViewerHostMsg_ImeCancelComposition);
-}
-
-void RemoteWindowTreeHostWin::OnTextInputClientUpdated(
-    const std::vector<int32_t>& input_scopes,
-    const std::vector<gfx::Rect>& composition_character_bounds) {
-  if (!host_)
-    return;
-  std::vector<metro_viewer::CharacterBounds> character_bounds;
-  for (size_t i = 0; i < composition_character_bounds.size(); ++i) {
-    const gfx::Rect& rect = composition_character_bounds[i];
-    metro_viewer::CharacterBounds bounds;
-    bounds.left = rect.x();
-    bounds.top = rect.y();
-    bounds.right = rect.right();
-    bounds.bottom = rect.bottom();
-    character_bounds.push_back(bounds);
-  }
-  host_->Send(new MetroViewerHostMsg_ImeTextInputClientUpdated(
-      input_scopes, character_bounds));
-}
-
-gfx::Point PointFromNativeEvent(int32_t x, int32_t y) {
-  static float scale_factor = gfx::GetDPIScale();
-  gfx::Point result( x * scale_factor, y * scale_factor);
-  return result;
-}
-
-void RemoteWindowTreeHostWin::OnMouseMoved(int32_t x,
-                                           int32_t y,
-                                           int32_t flags) {
-  if (ignore_mouse_moves_until_set_cursor_ack_)
-    return;
-
-  gfx::Point location = PointFromNativeEvent(x, y);
-  ui::MouseEvent event(ui::ET_MOUSE_MOVED, location, location,
-                       ui::EventTimeForNow(), flags, 0);
-  SendEventToProcessor(&event);
-}
-
-void RemoteWindowTreeHostWin::OnMouseButton(
-    const MetroViewerHostMsg_MouseButtonParams& params) {
-  gfx::Point location = PointFromNativeEvent(params.x, params.y);
-  ui::MouseEvent mouse_event(
-      params.event_type, location, location, ui::EventTimeForNow(),
-      static_cast<int>(params.flags), static_cast<int>(params.changed_button));
-
-  SetEventFlags(params.flags | key_event_flags());
-  if (params.event_type == ui::ET_MOUSEWHEEL) {
-    int x_offset = params.is_horizontal_wheel ? params.extra : 0;
-    int y_offset = !params.is_horizontal_wheel ? params.extra : 0;
-    ui::MouseWheelEvent wheel_event(mouse_event, x_offset, y_offset);
-    SendEventToProcessor(&wheel_event);
-  } else if (params.event_type == ui::ET_MOUSE_PRESSED) {
-    // TODO(shrikant): Ideally modify code in event.cc by adding automatic
-    // tracking of double clicks in synthetic MouseEvent constructor code.
-    // Non-synthetic MouseEvent constructor code does automatically track
-    // this. Need to use some caution while modifying synthetic constructor
-    // as many tests and other code paths depend on it and apparently
-    // specifically depend on non implicit tracking of previous mouse event.
-    if (last_mouse_click_event_ &&
-        ui::MouseEvent::IsRepeatedClickEvent(mouse_event,
-                                             *last_mouse_click_event_)) {
-      mouse_event.SetClickCount(2);
-    } else {
-      mouse_event.SetClickCount(1);
-    }
-    last_mouse_click_event_ .reset(new ui::MouseEvent(mouse_event));
-    SendEventToProcessor(&mouse_event);
-  } else {
-    SendEventToProcessor(&mouse_event);
-  }
-}
-
-void RemoteWindowTreeHostWin::OnKeyDown(uint32_t vkey,
-                                        uint32_t repeat_count,
-                                        uint32_t scan_code,
-                                        uint32_t flags) {
-  DispatchKeyboardMessage(ui::ET_KEY_PRESSED, vkey, repeat_count, scan_code,
-                          flags, false);
-}
-
-void RemoteWindowTreeHostWin::OnKeyUp(uint32_t vkey,
-                                      uint32_t repeat_count,
-                                      uint32_t scan_code,
-                                      uint32_t flags) {
-  DispatchKeyboardMessage(ui::ET_KEY_RELEASED, vkey, repeat_count, scan_code,
-                          flags, false);
-}
-
-void RemoteWindowTreeHostWin::OnChar(uint32_t key_code,
-                                     uint32_t repeat_count,
-                                     uint32_t scan_code,
-                                     uint32_t flags) {
-  DispatchKeyboardMessage(ui::ET_KEY_PRESSED, key_code, repeat_count,
-                          scan_code, flags, true);
-}
-
-void RemoteWindowTreeHostWin::OnWindowActivated(bool repaint) {
-  OnHostActivated();
-  if (repaint && compositor())
-    compositor()->ScheduleFullRedraw();
-}
-
-void RemoteWindowTreeHostWin::OnEdgeGesture() {
-  ui::GestureEvent event(
-      0,
-      0,
-      0,
-      ui::EventTimeForNow(),
-      ui::GestureEventDetails(ui::ET_GESTURE_WIN8_EDGE_SWIPE));
-  SendEventToProcessor(&event);
-}
-
-void RemoteWindowTreeHostWin::OnTouchDown(int32_t x,
-                                          int32_t y,
-                                          uint64_t timestamp,
-                                          uint32_t pointer_id) {
-  gfx::Point location = PointFromNativeEvent(x, y);
-  ui::TouchEvent event(ui::ET_TOUCH_PRESSED,
-                       location,
-                       pointer_id,
-                       base::TimeDelta::FromMicroseconds(timestamp));
-  SendEventToProcessor(&event);
-}
-
-void RemoteWindowTreeHostWin::OnTouchUp(int32_t x,
-                                        int32_t y,
-                                        uint64_t timestamp,
-                                        uint32_t pointer_id) {
-  gfx::Point location = PointFromNativeEvent(x, y);
-  ui::TouchEvent event(ui::ET_TOUCH_RELEASED,
-                       location,
-                       pointer_id,
-                       base::TimeDelta::FromMicroseconds(timestamp));
-  SendEventToProcessor(&event);
-}
-
-void RemoteWindowTreeHostWin::OnTouchMoved(int32_t x,
-                                           int32_t y,
-                                           uint64_t timestamp,
-                                           uint32_t pointer_id) {
-  gfx::Point location = PointFromNativeEvent(x, y);
-  ui::TouchEvent event(ui::ET_TOUCH_MOVED,
-                       location,
-                       pointer_id,
-                       base::TimeDelta::FromMicroseconds(timestamp));
-  SendEventToProcessor(&event);
-}
-
-void RemoteWindowTreeHostWin::OnSetCursorPosAck() {
-  DCHECK_GT(ignore_mouse_moves_until_set_cursor_ack_, 0);
-  ignore_mouse_moves_until_set_cursor_ack_--;
-}
-
-ui::RemoteInputMethodPrivateWin*
-RemoteWindowTreeHostWin::GetRemoteInputMethodPrivate() {
-  return ui::RemoteInputMethodPrivateWin::Get(GetInputMethod());
-}
-
-void RemoteWindowTreeHostWin::OnImeCandidatePopupChanged(bool visible) {
-  ui::RemoteInputMethodPrivateWin* remote_input_method_private =
-      GetRemoteInputMethodPrivate();
-  if (!remote_input_method_private)
-    return;
-  remote_input_method_private->OnCandidatePopupChanged(visible);
-}
-
-void RemoteWindowTreeHostWin::OnImeCompositionChanged(
-    const base::string16& text,
-    int32_t selection_start,
-    int32_t selection_end,
-    const std::vector<metro_viewer::UnderlineInfo>& underlines) {
-  ui::RemoteInputMethodPrivateWin* remote_input_method_private =
-      GetRemoteInputMethodPrivate();
-  if (!remote_input_method_private)
-    return;
-  ui::CompositionText composition_text;
-  FillCompositionText(
-      text, selection_start, selection_end, underlines, &composition_text);
-  remote_input_method_private->OnCompositionChanged(composition_text);
-}
-
-void RemoteWindowTreeHostWin::OnImeTextCommitted(const base::string16& text) {
-  ui::RemoteInputMethodPrivateWin* remote_input_method_private =
-      GetRemoteInputMethodPrivate();
-  if (!remote_input_method_private)
-    return;
-  remote_input_method_private->OnTextCommitted(text);
-}
-
-void RemoteWindowTreeHostWin::OnImeInputSourceChanged(uint16_t language_id,
-                                                      bool is_ime) {
-  ui::RemoteInputMethodPrivateWin* remote_input_method_private =
-      GetRemoteInputMethodPrivate();
-  if (!remote_input_method_private)
-    return;
-  remote_input_method_private->OnInputSourceChanged(language_id, is_ime);
-}
-
-void RemoteWindowTreeHostWin::DispatchKeyboardMessage(ui::EventType type,
-                                                      uint32_t vkey,
-                                                      uint32_t repeat_count,
-                                                      uint32_t scan_code,
-                                                      uint32_t flags,
-                                                      bool is_character) {
-  SetEventFlags(flags | mouse_event_flags());
-  if (base::MessageLoop::current()->IsNested()) {
-    int index = (flags & ui::EF_ALT_DOWN) ? 1 : 0;
-    const int char_message[] = {WM_CHAR, WM_SYSCHAR};
-    const int keydown_message[] = {WM_KEYDOWN, WM_SYSKEYDOWN};
-    const int keyup_message[] = {WM_KEYUP, WM_SYSKEYUP};
-    uint32_t message =
-        is_character ? char_message[index]
-                     : (type == ui::ET_KEY_PRESSED ? keydown_message[index]
-                                                   : keyup_message[index]);
-    ::PostThreadMessage(::GetCurrentThreadId(),
-                        message,
-                        vkey,
-                        repeat_count | scan_code >> 15);
-  } else if (is_character) {
-    ui::KeyEvent event(static_cast<base::char16>(vkey),
-                       ui::KeyboardCodeForWindowsKeyCode(vkey),
-                       flags);
-    SendEventToProcessor(&event);
-  } else {
-    ui::KeyEvent event(type,
-                       ui::KeyboardCodeForWindowsKeyCode(vkey),
-                       flags);
-    SendEventToProcessor(&event);
-  }
-}
-
-void RemoteWindowTreeHostWin::SetEventFlags(uint32_t flags) {
-  if (flags == event_flags_)
-    return;
-  event_flags_ = flags;
-  SetVirtualKeyStates(event_flags_);
-}
-
-}  // namespace aura
diff --git a/ui/aura/remote_window_tree_host_win.h b/ui/aura/remote_window_tree_host_win.h
deleted file mode 100644
index 4614fd6e..0000000
--- a/ui/aura/remote_window_tree_host_win.h
+++ /dev/null
@@ -1,197 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_AURA_REMOTE_WINDOW_TREE_HOST_WIN_H_
-#define UI_AURA_REMOTE_WINDOW_TREE_HOST_WIN_H_
-
-#include <stdint.h>
-
-#include <vector>
-
-#include "base/compiler_specific.h"
-#include "base/macros.h"
-#include "base/strings/string16.h"
-#include "ui/aura/window_tree_host.h"
-#include "ui/base/ime/remote_input_method_delegate_win.h"
-#include "ui/events/event.h"
-#include "ui/events/event_constants.h"
-#include "ui/events/event_source.h"
-#include "ui/gfx/native_widget_types.h"
-#include "ui/metro_viewer/ime_types.h"
-
-struct MetroViewerHostMsg_MouseButtonParams;
-
-namespace base {
-class FilePath;
-}
-
-namespace ui {
-class RemoteInputMethodPrivateWin;
-class ViewProp;
-}
-
-namespace IPC {
-class Message;
-class Sender;
-}
-
-namespace aura {
-
-// WindowTreeHost implementaton that receives events from a different
-// process. In the case of Windows this is the Windows 8 (aka Metro)
-// frontend process, which forwards input events to this class.
-class AURA_EXPORT RemoteWindowTreeHostWin
-    : public WindowTreeHost,
-      public ui::internal::RemoteInputMethodDelegateWin {
- public:
-  // Returns the current RemoteWindowTreeHostWin. This does *not* create a
-  // RemoteWindowTreeHostWin.
-  static RemoteWindowTreeHostWin* Instance();
-
-  // Returns true if there is a RemoteWindowTreeHostWin and it has a valid
-  // HWND. A return value of false typically indicates we're not in metro mode.
-  static bool IsValid();
-
-  // Sets the handle to the remote window. The |remote_window| is the actual
-  // window owned by the viewer process. Call this before Connected() for some
-  // customers like input method initialization which needs the handle.
-  void SetRemoteWindowHandle(HWND remote_window);
-  HWND remote_window() { return remote_window_; }
-
-  // The |host| can be used when we need to send a message to it.
-  void Connected(IPC::Sender* host);
-  // Called when the remote process has closed its IPC connection.
-  void Disconnected();
-
-  // Called when we have a message from the remote process.
-  bool OnMessageReceived(const IPC::Message& message);
-
-  void HandleOpenURLOnDesktop(const base::FilePath& shortcut,
-                              const base::string16& url);
-
-  void HandleWindowSizeChanged(uint32_t width, uint32_t height);
-
-  // Returns the active ASH root window.
-  Window* GetAshWindow();
-
-  // Returns true if the remote window is the foreground window according to the
-  // OS.
-  bool IsForegroundWindow();
-
- protected:
-  RemoteWindowTreeHostWin();
-  ~RemoteWindowTreeHostWin() override;
-
- private:
-  // IPC message handing methods:
-  void OnMouseMoved(int32_t x, int32_t y, int32_t flags);
-  void OnMouseButton(const MetroViewerHostMsg_MouseButtonParams& params);
-  void OnKeyDown(uint32_t vkey,
-                 uint32_t repeat_count,
-                 uint32_t scan_code,
-                 uint32_t flags);
-  void OnKeyUp(uint32_t vkey,
-               uint32_t repeat_count,
-               uint32_t scan_code,
-               uint32_t flags);
-  void OnChar(uint32_t key_code,
-              uint32_t repeat_count,
-              uint32_t scan_code,
-              uint32_t flags);
-  void OnWindowActivated(bool repaint);
-  void OnEdgeGesture();
-  void OnTouchDown(int32_t x,
-                   int32_t y,
-                   uint64_t timestamp,
-                   uint32_t pointer_id);
-  void OnTouchUp(int32_t x, int32_t y, uint64_t timestamp, uint32_t pointer_id);
-  void OnTouchMoved(int32_t x,
-                    int32_t y,
-                    uint64_t timestamp,
-                    uint32_t pointer_id);
-  void OnSetCursorPosAck();
-
-  // For Input Method support:
-  ui::RemoteInputMethodPrivateWin* GetRemoteInputMethodPrivate();
-  void OnImeCandidatePopupChanged(bool visible);
-  void OnImeCompositionChanged(
-      const base::string16& text,
-      int32_t selection_start,
-      int32_t selection_end,
-      const std::vector<metro_viewer::UnderlineInfo>& underlines);
-  void OnImeTextCommitted(const base::string16& text);
-  void OnImeInputSourceChanged(uint16_t language_id, bool is_ime);
-
-  // WindowTreeHost overrides:
-  ui::EventSource* GetEventSource() override;
-  gfx::AcceleratedWidget GetAcceleratedWidget() override;
-  void ShowImpl() override;
-  void HideImpl() override;
-  gfx::Rect GetBounds() const override;
-  void SetBounds(const gfx::Rect& bounds) override;
-  gfx::Point GetLocationOnNativeScreen() const override;
-  void SetCapture() override;
-  void ReleaseCapture() override;
-  void SetCursorNative(gfx::NativeCursor cursor) override;
-  void MoveCursorToNative(const gfx::Point& location) override;
-  void OnCursorVisibilityChangedNative(bool show) override;
-
-  // ui::internal::RemoteInputMethodDelegateWin overrides:
-  void CancelComposition() override;
-  void OnTextInputClientUpdated(
-      const std::vector<int32_t>& input_scopes,
-      const std::vector<gfx::Rect>& composition_character_bounds) override;
-
-  // Helper function to dispatch a keyboard message to the desired target.
-  // The default target is the WindowEventDispatcher. For nested message loop
-  // invocations we post a synthetic keyboard message directly into the message
-  // loop. The dispatcher for the nested loop would then decide how this
-  // message is routed.
-  void DispatchKeyboardMessage(ui::EventType type,
-                               uint32_t vkey,
-                               uint32_t repeat_count,
-                               uint32_t scan_code,
-                               uint32_t flags,
-                               bool is_character);
-
-  // Sets the event flags. |flags| is a bitmask of EventFlags. If there is a
-  // change the system virtual key state is updated as well. This way if chrome
-  // queries for key state it matches that of event being dispatched.
-  void SetEventFlags(uint32_t flags);
-
-  uint32_t mouse_event_flags() const {
-    return event_flags_ & (ui::EF_LEFT_MOUSE_BUTTON |
-                           ui::EF_MIDDLE_MOUSE_BUTTON |
-                           ui::EF_RIGHT_MOUSE_BUTTON);
-  }
-
-  uint32_t key_event_flags() const {
-    return event_flags_ & (ui::EF_SHIFT_DOWN | ui::EF_CONTROL_DOWN |
-                           ui::EF_ALT_DOWN | ui::EF_CAPS_LOCK_ON);
-  }
-
-  HWND remote_window_;
-  IPC::Sender* host_;
-  scoped_ptr<ui::ViewProp> prop_;
-
-  // Incremented if we need to ignore mouse messages until the SetCursorPos
-  // operation is acked by the viewer.
-  int ignore_mouse_moves_until_set_cursor_ack_;
-
-  // Tracking last click event for synthetically generated mouse events.
-  scoped_ptr<ui::MouseEvent> last_mouse_click_event_;
-
-  // State of the keyboard/mouse at the time of the last input event. See
-  // description of SetEventFlags().
-  uint32_t event_flags_;
-
-  // Current size of this root window.
-  gfx::Size window_size_;
-
-  DISALLOW_COPY_AND_ASSIGN(RemoteWindowTreeHostWin);
-};
-
-}  // namespace aura
-
-#endif  // UI_AURA_REMOTE_WINDOW_TREE_HOST_WIN_H_
diff --git a/ui/base/BUILD.gn b/ui/base/BUILD.gn
index 6190b065..e2fa018 100644
--- a/ui/base/BUILD.gn
+++ b/ui/base/BUILD.gn
@@ -743,7 +743,6 @@
       "ime/composition_text_unittest.cc",
       "ime/input_method_base_unittest.cc",
       "ime/input_method_chromeos_unittest.cc",
-      "ime/remote_input_method_win_unittest.cc",
       "ime/win/imm32_manager_unittest.cc",
       "ime/win/tsf_input_scope_unittest.cc",
     ]
diff --git a/ui/base/ime/BUILD.gn b/ui/base/ime/BUILD.gn
index f729482..9cf4606b 100644
--- a/ui/base/ime/BUILD.gn
+++ b/ui/base/ime/BUILD.gn
@@ -83,9 +83,6 @@
     "linux/linux_input_method_context_factory.h",
     "mock_input_method.cc",
     "mock_input_method.h",
-    "remote_input_method_delegate_win.h",
-    "remote_input_method_win.cc",
-    "remote_input_method_win.h",
     "text_input_client.cc",
     "text_input_client.h",
     "text_input_type.h",
diff --git a/ui/base/ime/input_method_factory.cc b/ui/base/ime/input_method_factory.cc
index dd9d31a..1fda6daa 100644
--- a/ui/base/ime/input_method_factory.cc
+++ b/ui/base/ime/input_method_factory.cc
@@ -11,7 +11,6 @@
 #include "ui/base/ime/input_method_chromeos.h"
 #elif defined(OS_WIN)
 #include "ui/base/ime/input_method_win.h"
-#include "ui/base/ime/remote_input_method_win.h"
 #elif defined(OS_MACOSX)
 #include "ui/base/ime/input_method_mac.h"
 #elif defined(USE_AURA) && defined(OS_LINUX) && defined(USE_X11) && \
@@ -53,8 +52,6 @@
 #if defined(OS_CHROMEOS)
   return make_scoped_ptr(new InputMethodChromeOS(delegate));
 #elif defined(OS_WIN)
-  if (IsRemoteInputMethodWinRequired(widget))
-    return CreateRemoteInputMethodWin(delegate);
   return make_scoped_ptr(new InputMethodWin(delegate, widget));
 #elif defined(OS_MACOSX)
   return make_scoped_ptr(new InputMethodMac(delegate));
diff --git a/ui/base/ime/remote_input_method_delegate_win.h b/ui/base/ime/remote_input_method_delegate_win.h
deleted file mode 100644
index a172c7b5..0000000
--- a/ui/base/ime/remote_input_method_delegate_win.h
+++ /dev/null
@@ -1,42 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_BASE_IME_REMOTE_INPUT_METHOD_DELEGATE_WIN_H_
-#define UI_BASE_IME_REMOTE_INPUT_METHOD_DELEGATE_WIN_H_
-
-#include <stdint.h>
-
-#include <vector>
-
-#include "ui/base/ime/ui_base_ime_export.h"
-#include "ui/gfx/geometry/rect.h"
-
-namespace ui {
-namespace internal {
-
-// An interface implemented by the object to forward events that should be
-// handled by the IME which is running in the remote metro_driver process.
-class UI_BASE_IME_EXPORT RemoteInputMethodDelegateWin {
- public:
-  virtual ~RemoteInputMethodDelegateWin() {}
-
-  // Notifies that composition should be canceled (if any).
-  virtual void CancelComposition() = 0;
-
-  // Notifies that properties of the focused TextInputClient is changed.
-  // Note that an empty |input_scopes| represents that TextInputType is
-  // TEXT_INPUT_TYPE_NONE.
-  // Caveats: |input_scopes| is defined as std::vector<int32_t> rather than
-  // std::vector<InputScope> because the wire format of IPC message
-  // MetroViewerHostMsg_ImeTextInputClientUpdated uses std::vector<int32_t> to
-  // avoid dependency on <InputScope.h> header.
-  virtual void OnTextInputClientUpdated(
-      const std::vector<int32_t>& input_scopes,
-      const std::vector<gfx::Rect>& composition_character_bounds) = 0;
-};
-
-}  // namespace internal
-}  // namespace ui
-
-#endif  // UI_BASE_IME_REMOTE_INPUT_METHOD_DELEGATE_WIN_H_
diff --git a/ui/base/ime/remote_input_method_win.cc b/ui/base/ime/remote_input_method_win.cc
deleted file mode 100644
index 27d242a..0000000
--- a/ui/base/ime/remote_input_method_win.cc
+++ /dev/null
@@ -1,385 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/base/ime/remote_input_method_win.h"
-
-#include <stddef.h>
-#include <stdint.h>
-
-#include "base/command_line.h"
-#include "base/macros.h"
-#include "base/observer_list.h"
-#include "base/strings/utf_string_conversions.h"
-#include "base/win/scoped_handle.h"
-#include "ui/base/ime/input_method.h"
-#include "ui/base/ime/input_method_delegate.h"
-#include "ui/base/ime/input_method_observer.h"
-#include "ui/base/ime/remote_input_method_delegate_win.h"
-#include "ui/base/ime/text_input_client.h"
-#include "ui/base/ime/win/tsf_input_scope.h"
-#include "ui/base/ui_base_switches.h"
-#include "ui/events/event.h"
-#include "ui/events/event_utils.h"
-#include "ui/gfx/geometry/rect.h"
-
-namespace ui {
-namespace {
-
-const LANGID kFallbackLangID =
-    MAKELANGID(LANG_NEUTRAL, SUBLANG_UI_CUSTOM_DEFAULT);
-
-InputMethod* g_public_interface_ = NULL;
-RemoteInputMethodPrivateWin* g_private_interface_ = NULL;
-
-void RegisterInstance(InputMethod* public_interface,
-                      RemoteInputMethodPrivateWin* private_interface) {
-  CHECK(g_public_interface_ == NULL)
-      << "Only one instance is supported at the same time";
-  CHECK(g_private_interface_ == NULL)
-      << "Only one instance is supported at the same time";
-  g_public_interface_ = public_interface;
-  g_private_interface_ = private_interface;
-}
-
-RemoteInputMethodPrivateWin* GetPrivate(InputMethod* public_interface) {
-  if (g_public_interface_ != public_interface)
-    return NULL;
-  return g_private_interface_;
-}
-
-void UnregisterInstance(InputMethod* public_interface) {
-  RemoteInputMethodPrivateWin* private_interface = GetPrivate(public_interface);
-  if (g_public_interface_ == public_interface &&
-      g_private_interface_ == private_interface) {
-    g_public_interface_ = NULL;
-    g_private_interface_ = NULL;
-  }
-}
-
-std::string GetLocaleString(LCID Locale_id, LCTYPE locale_type) {
-  wchar_t buffer[16] = {};
-
-  //|chars_written| includes NUL terminator.
-  const int chars_written =
-      GetLocaleInfo(Locale_id, locale_type, buffer, arraysize(buffer));
-  if (chars_written <= 1 || static_cast<int>(arraysize(buffer)) < chars_written)
-    return std::string();
-  std::string result;
-  base::WideToUTF8(buffer, chars_written - 1, &result);
-  return result;
-}
-
-std::vector<int32_t> GetInputScopesAsInt(TextInputType text_input_type,
-                                         TextInputMode text_input_mode) {
-  std::vector<int32_t> result;
-  // An empty vector represents |text_input_type| is TEXT_INPUT_TYPE_NONE.
-  if (text_input_type == TEXT_INPUT_TYPE_NONE)
-    return result;
-
-  const std::vector<InputScope>& input_scopes =
-      tsf_inputscope::GetInputScopes(text_input_type, text_input_mode);
-  result.reserve(input_scopes.size());
-  for (size_t i = 0; i < input_scopes.size(); ++i)
-    result.push_back(static_cast<int32_t>(input_scopes[i]));
-  return result;
-}
-
-std::vector<gfx::Rect> GetCompositionCharacterBounds(
-    const TextInputClient* client) {
-  if (!client)
-    return std::vector<gfx::Rect>();
-
-  std::vector<gfx::Rect> bounds;
-  if (client->HasCompositionText()) {
-    gfx::Range range;
-    if (client->GetCompositionTextRange(&range)) {
-      for (uint32_t i = 0; i < range.length(); ++i) {
-        gfx::Rect rect;
-        if (!client->GetCompositionCharacterBounds(i, &rect))
-          break;
-        bounds.push_back(rect);
-      }
-    }
-  }
-
-  // Use the caret bounds as a fallback if no composition character bounds is
-  // available. One typical use case is PPAPI Flash, which does not support
-  // GetCompositionCharacterBounds at all. crbug.com/133472
-  if (bounds.empty())
-    bounds.push_back(client->GetCaretBounds());
-  return bounds;
-}
-
-class RemoteInputMethodWin : public InputMethod,
-                             public RemoteInputMethodPrivateWin {
- public:
-  explicit RemoteInputMethodWin(internal::InputMethodDelegate* delegate)
-      : delegate_(delegate),
-        remote_delegate_(NULL),
-        text_input_client_(NULL),
-        is_candidate_popup_open_(false),
-        is_ime_(false),
-        langid_(kFallbackLangID) {
-    RegisterInstance(this, this);
-  }
-
-  ~RemoteInputMethodWin() override {
-    FOR_EACH_OBSERVER(InputMethodObserver,
-                      observer_list_,
-                      OnInputMethodDestroyed(this));
-    UnregisterInstance(this);
-  }
-
- private:
-  // Overridden from InputMethod:
-  void SetDelegate(internal::InputMethodDelegate* delegate) override {
-    delegate_ = delegate;
-  }
-
-  void OnFocus() override {}
-
-  void OnBlur() override {}
-
-  bool OnUntranslatedIMEMessage(const base::NativeEvent& event,
-                                NativeEventResult* result) override {
-    return false;
-  }
-
-  void SetFocusedTextInputClient(TextInputClient* client) override {
-    std::vector<int32_t> prev_input_scopes;
-    std::swap(input_scopes_, prev_input_scopes);
-    std::vector<gfx::Rect> prev_bounds;
-    std::swap(composition_character_bounds_, prev_bounds);
-    if (client) {
-      input_scopes_ = GetInputScopesAsInt(client->GetTextInputType(),
-                                          client->GetTextInputMode());
-      composition_character_bounds_ = GetCompositionCharacterBounds(client);
-    }
-
-    const bool text_input_client_changed = text_input_client_ != client;
-    text_input_client_ = client;
-    if (text_input_client_changed) {
-      FOR_EACH_OBSERVER(InputMethodObserver,
-                        observer_list_,
-                        OnTextInputStateChanged(client));
-    }
-
-    if (!remote_delegate_ || (prev_input_scopes == input_scopes_ &&
-                              prev_bounds == composition_character_bounds_))
-      return;
-    remote_delegate_->OnTextInputClientUpdated(input_scopes_,
-                                               composition_character_bounds_);
-  }
-
-  void DetachTextInputClient(TextInputClient* client) override {
-    if (text_input_client_ != client)
-      return;
-    SetFocusedTextInputClient(NULL);
-  }
-
-  TextInputClient* GetTextInputClient() const override {
-    return text_input_client_;
-  }
-
-  void DispatchKeyEvent(ui::KeyEvent* event) override {
-    if (event->HasNativeEvent()) {
-      const base::NativeEvent& native_key_event = event->native_event();
-      if (native_key_event.message == WM_CHAR && text_input_client_) {
-        text_input_client_->InsertChar(*event);
-        event->StopPropagation();
-      }
-      return;
-    }
-
-    if (event->is_char()) {
-      if (text_input_client_) {
-        text_input_client_->InsertChar(*event);
-      }
-      event->StopPropagation();
-      return;
-    }
-    if (delegate_)
-      ignore_result(delegate_->DispatchKeyEventPostIME(event));
-  }
-
-  void OnTextInputTypeChanged(const TextInputClient* client) override {
-    if (!text_input_client_ || text_input_client_ != client)
-      return;
-    std::vector<int32_t> prev_input_scopes;
-    std::swap(input_scopes_, prev_input_scopes);
-    input_scopes_ = GetInputScopesAsInt(client->GetTextInputType(),
-                                        client->GetTextInputMode());
-    if (input_scopes_ != prev_input_scopes && remote_delegate_) {
-      remote_delegate_->OnTextInputClientUpdated(
-          input_scopes_, composition_character_bounds_);
-    }
-  }
-
-  void OnCaretBoundsChanged(const TextInputClient* client) override {
-    if (!text_input_client_ || text_input_client_ != client)
-      return;
-    std::vector<gfx::Rect> prev_rects;
-    std::swap(composition_character_bounds_, prev_rects);
-    composition_character_bounds_ = GetCompositionCharacterBounds(client);
-    if (composition_character_bounds_ != prev_rects && remote_delegate_) {
-      remote_delegate_->OnTextInputClientUpdated(
-          input_scopes_, composition_character_bounds_);
-    }
-  }
-
-  void CancelComposition(const TextInputClient* client) override {
-    if (CanSendRemoteNotification(client))
-      remote_delegate_->CancelComposition();
-  }
-
-  void OnInputLocaleChanged() override {}
-
-  std::string GetInputLocale() override {
-    const LCID locale_id = MAKELCID(langid_, SORT_DEFAULT);
-    std::string language =
-        GetLocaleString(locale_id, LOCALE_SISO639LANGNAME);
-    if (SUBLANGID(langid_) == SUBLANG_NEUTRAL || language.empty())
-      return language;
-    const std::string& region =
-        GetLocaleString(locale_id, LOCALE_SISO3166CTRYNAME);
-    if (region.empty())
-      return language;
-    return language.append(1, '-').append(region);
-  }
-
-  TextInputType GetTextInputType() const override {
-    return text_input_client_ ? text_input_client_->GetTextInputType()
-                              : TEXT_INPUT_TYPE_NONE;
-  }
-
-  TextInputMode GetTextInputMode() const override {
-    return text_input_client_ ? text_input_client_->GetTextInputMode()
-                              : TEXT_INPUT_MODE_DEFAULT;
-  }
-
-  int GetTextInputFlags() const override {
-    return text_input_client_ ? text_input_client_->GetTextInputFlags()
-                              : 0;
-  }
-
-  bool CanComposeInline() const override {
-    return text_input_client_ ? text_input_client_->CanComposeInline() : true;
-  }
-
-  bool IsCandidatePopupOpen() const override {
-    return is_candidate_popup_open_;
-  }
-
-  void ShowImeIfNeeded() override {}
-
-  void AddObserver(InputMethodObserver* observer) override {
-    observer_list_.AddObserver(observer);
-  }
-
-  void RemoveObserver(InputMethodObserver* observer) override {
-    observer_list_.RemoveObserver(observer);
-  }
-
-  // Overridden from RemoteInputMethodPrivateWin:
-  void SetRemoteDelegate(
-      internal::RemoteInputMethodDelegateWin* delegate) override {
-    remote_delegate_ = delegate;
-
-    // Sync initial state.
-    if (remote_delegate_) {
-      remote_delegate_->OnTextInputClientUpdated(
-          input_scopes_, composition_character_bounds_);
-    }
-  }
-
-  void OnCandidatePopupChanged(bool visible) override {
-    is_candidate_popup_open_ = visible;
-  }
-
-  void OnInputSourceChanged(LANGID langid, bool /*is_ime*/) override {
-    // Note: Currently |is_ime| is not utilized yet.
-    const bool changed = (langid_ != langid);
-    langid_ = langid;
-    if (changed && GetTextInputClient())
-      GetTextInputClient()->OnInputMethodChanged();
-  }
-
-  void OnCompositionChanged(const CompositionText& composition_text) override {
-    if (!text_input_client_)
-      return;
-    text_input_client_->SetCompositionText(composition_text);
-  }
-
-  void OnTextCommitted(const base::string16& text) override {
-    if (!text_input_client_)
-      return;
-    if (text_input_client_->GetTextInputType() == TEXT_INPUT_TYPE_NONE) {
-      // According to the comment in text_input_client.h,
-      // TextInputClient::InsertText should never be called when the
-      // text input type is TEXT_INPUT_TYPE_NONE.
-
-      for (size_t i = 0; i < text.size(); ++i) {
-        ui::KeyEvent char_event(text[i], static_cast<ui::KeyboardCode>(text[i]),
-                                ui::EF_NONE);
-        text_input_client_->InsertChar(char_event);
-      }
-      return;
-    }
-    text_input_client_->InsertText(text);
-  }
-
-  bool CanSendRemoteNotification(
-      const TextInputClient* text_input_client) const {
-    return text_input_client_ &&
-           text_input_client_ == text_input_client &&
-           remote_delegate_;
-  }
-
-  base::ObserverList<InputMethodObserver> observer_list_;
-
-  internal::InputMethodDelegate* delegate_;
-  internal::RemoteInputMethodDelegateWin* remote_delegate_;
-
-  TextInputClient* text_input_client_;
-  std::vector<int32_t> input_scopes_;
-  std::vector<gfx::Rect> composition_character_bounds_;
-  bool is_candidate_popup_open_;
-  bool is_ime_;
-  LANGID langid_;
-
-  DISALLOW_COPY_AND_ASSIGN(RemoteInputMethodWin);
-};
-
-}  // namespace
-
-bool IsRemoteInputMethodWinRequired(gfx::AcceleratedWidget widget) {
-  // If the remote input method is already registered then don't do it again.
-  if (ui::g_public_interface_ && ui::g_private_interface_)
-    return false;
-
-  DWORD process_id = 0;
-  if (GetWindowThreadProcessId(widget, &process_id) == 0)
-    return false;
-  base::win::ScopedHandle process_handle(::OpenProcess(
-      PROCESS_QUERY_LIMITED_INFORMATION, FALSE, process_id));
-  if (!process_handle.IsValid())
-    return false;
-  return base::CommandLine::ForCurrentProcess()->HasSwitch(
-      switches::kViewerConnect);
-}
-
-RemoteInputMethodPrivateWin::RemoteInputMethodPrivateWin() {}
-
-scoped_ptr<InputMethod> CreateRemoteInputMethodWin(
-    internal::InputMethodDelegate* delegate) {
-  return make_scoped_ptr(new RemoteInputMethodWin(delegate));
-}
-
-// static
-RemoteInputMethodPrivateWin* RemoteInputMethodPrivateWin::Get(
-    InputMethod* input_method) {
-  return GetPrivate(input_method);
-}
-
-}  // namespace ui
diff --git a/ui/base/ime/remote_input_method_win.h b/ui/base/ime/remote_input_method_win.h
deleted file mode 100644
index a1725b32..0000000
--- a/ui/base/ime/remote_input_method_win.h
+++ /dev/null
@@ -1,100 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_BASE_IME_REMOTE_INPUT_METHOD_WIN_H_
-#define UI_BASE_IME_REMOTE_INPUT_METHOD_WIN_H_
-
-#include <Windows.h>
-
-#include <string>
-
-#include "base/compiler_specific.h"
-#include "base/macros.h"
-#include "base/memory/scoped_ptr.h"
-#include "base/strings/string16.h"
-#include "ui/base/ime/ui_base_ime_export.h"
-#include "ui/gfx/native_widget_types.h"
-
-namespace ui {
-namespace internal {
-class InputMethodDelegate;
-class RemoteInputMethodDelegateWin;
-}  // namespace internal
-
-class InputMethod;
-struct CompositionText;
-
-// RemoteInputMethodWin is a special implementation of ui::InputMethod that
-// works as a proxy of an IME handler running in the metro_driver process.
-// RemoteInputMethodWin works as follows.
-// - Any action to RemoteInputMethodWin should be delegated to the
-//   metro_driver process via RemoteInputMethodDelegateWin.
-// - Data retrieval from RemoteInputMethodPrivateWin is implemented with
-//   data cache. Whenever the IME state in the metro_driver process is changed,
-//   RemoteWindowTreeHostWin, which receives IPCs from metro_driver process,
-//   will call RemoteInputMethodPrivateWin::OnCandidatePopupChanged and/or
-//   RemoteInputMethodPrivateWin::OnInputSourceChanged accordingly so that
-//   the state cache should be updated.
-// - Some IPC messages that represent actions to TextInputClient should be
-//   delegated to RemoteInputMethodPrivateWin so that RemoteInputMethodWin can
-//   work as a real proxy.
-
-// Returns true if |widget| requires RemoteInputMethodWin.
-bool IsRemoteInputMethodWinRequired(gfx::AcceleratedWidget widget);
-
-// Returns the public interface of RemoteInputMethodWin.
-// Caveats: Currently only one instance of RemoteInputMethodWin is able to run
-// at the same time.
-UI_BASE_IME_EXPORT scoped_ptr<InputMethod> CreateRemoteInputMethodWin(
-    internal::InputMethodDelegate* delegate);
-
-// Private interface of RemoteInputMethodWin.
-class UI_BASE_IME_EXPORT RemoteInputMethodPrivateWin {
- public:
-  RemoteInputMethodPrivateWin();
-
-  // Returns the private interface of RemoteInputMethodWin when and only when
-  // |input_method| is instanciated via CreateRemoteInputMethodWin. Caller does
-  // not take the ownership of the returned object.
-  // As you might notice, this is yet another reinplementation of dynamic_cast
-  // or IUnknown::QueryInterface.
-  static RemoteInputMethodPrivateWin* Get(InputMethod* input_method);
-
-  // Installs RemoteInputMethodDelegateWin delegate. Set NULL to |delegate| to
-  // unregister.
-  virtual void SetRemoteDelegate(
-      internal::RemoteInputMethodDelegateWin* delegate) = 0;
-
-  // Updates internal cache so that subsequent calls of
-  // RemoteInputMethodWin::IsCandidatePopupOpen can return the correct value
-  // based on remote IME activities in the metro_driver process.
-  virtual void OnCandidatePopupChanged(bool visible) = 0;
-
-  // Updates internal cache so that subsequent calls of
-  // RemoteInputMethodWin::GetInputLocale can return the correct values based on
-  // remote IME activities in the metro_driver process.
-  virtual void OnInputSourceChanged(LANGID langid, bool is_ime) = 0;
-
-  // Handles composition-update events occurred in the metro_driver process.
-  // Caveats: This method is designed to be used only with
-  // metro_driver::TextService. In other words, there is no garantee that this
-  // method works a wrapper to call ui::TextInputClient::SetCompositionText.
-  virtual void OnCompositionChanged(
-      const CompositionText& composition_text) = 0;
-
-  // Handles text-commit events occurred in the metro_driver process.
-  // Caveats: This method is designed to be used only with
-  // metro_driver::TextService. In other words, there is no garantee that this
-  // method works a wrapper to call ui::TextInputClient::InsertText. In fact,
-  // this method may call ui::TextInputClient::InsertChar when the text input
-  // type of the focused text input client is TEXT_INPUT_TYPE_NONE.
-  virtual void OnTextCommitted(const base::string16& text) = 0;
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(RemoteInputMethodPrivateWin);
-};
-
-}  // namespace ui
-
-#endif  // UI_BASE_IME_REMOTE_INPUT_METHOD_WIN_H_
diff --git a/ui/base/ime/remote_input_method_win_unittest.cc b/ui/base/ime/remote_input_method_win_unittest.cc
deleted file mode 100644
index 2d15919..0000000
--- a/ui/base/ime/remote_input_method_win_unittest.cc
+++ /dev/null
@@ -1,831 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/base/ime/remote_input_method_win.h"
-
-#include <InputScope.h>
-#include <stddef.h>
-#include <stdint.h>
-
-#include <vector>
-
-#include "base/macros.h"
-#include "base/memory/scoped_ptr.h"
-#include "base/scoped_observer.h"
-#include "base/strings/string16.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "ui/base/ime/composition_text.h"
-#include "ui/base/ime/dummy_text_input_client.h"
-#include "ui/base/ime/input_method.h"
-#include "ui/base/ime/input_method_delegate.h"
-#include "ui/base/ime/input_method_observer.h"
-#include "ui/base/ime/remote_input_method_delegate_win.h"
-#include "ui/events/event.h"
-
-namespace ui {
-namespace {
-
-class MockTextInputClient : public DummyTextInputClient {
- public:
-  MockTextInputClient()
-      : text_input_type_(TEXT_INPUT_TYPE_NONE),
-        text_input_mode_(TEXT_INPUT_MODE_DEFAULT),
-        call_count_set_composition_text_(0),
-        call_count_insert_char_(0),
-        call_count_insert_text_(0),
-        emulate_pepper_flash_(false) {
-  }
-
-  size_t call_count_set_composition_text() const {
-    return call_count_set_composition_text_;
-  }
-  const base::string16& inserted_text() const {
-    return inserted_text_;
-  }
-  size_t call_count_insert_char() const {
-    return call_count_insert_char_;
-  }
-  size_t call_count_insert_text() const {
-    return call_count_insert_text_;
-  }
-  void Reset() {
-    text_input_type_ = TEXT_INPUT_TYPE_NONE;
-    text_input_mode_ = TEXT_INPUT_MODE_DEFAULT;
-    call_count_set_composition_text_ = 0;
-    inserted_text_.clear();
-    call_count_insert_char_ = 0;
-    call_count_insert_text_ = 0;
-    caret_bounds_ = gfx::Rect();
-    composition_character_bounds_.clear();
-    emulate_pepper_flash_ = false;
-  }
-  void set_text_input_type(ui::TextInputType type) {
-    text_input_type_ = type;
-  }
-  void set_text_input_mode(ui::TextInputMode mode) {
-    text_input_mode_ = mode;
-  }
-  void set_caret_bounds(const gfx::Rect& caret_bounds) {
-    caret_bounds_ = caret_bounds;
-  }
-  void set_composition_character_bounds(
-      const std::vector<gfx::Rect>& composition_character_bounds) {
-    composition_character_bounds_ = composition_character_bounds;
-  }
-  void set_emulate_pepper_flash(bool enabled) {
-    emulate_pepper_flash_ = enabled;
-  }
-
- private:
-  // Overriden from DummyTextInputClient.
-  void SetCompositionText(const ui::CompositionText& composition) override {
-    ++call_count_set_composition_text_;
-  }
-  void InsertChar(const ui::KeyEvent& event) override {
-    inserted_text_.append(1, event.GetCharacter());
-    ++call_count_insert_char_;
-  }
-  void InsertText(const base::string16& text) override {
-    inserted_text_.append(text);
-    ++call_count_insert_text_;
-  }
-  ui::TextInputType GetTextInputType() const override {
-    return text_input_type_;
-  }
-  ui::TextInputMode GetTextInputMode() const override {
-    return text_input_mode_;
-  }
-  gfx::Rect GetCaretBounds() const override { return caret_bounds_; }
-  bool GetCompositionCharacterBounds(uint32_t index,
-                                     gfx::Rect* rect) const override {
-    // Emulate the situation of crbug.com/328237.
-    if (emulate_pepper_flash_)
-      return false;
-    if (!rect || composition_character_bounds_.size() <= index)
-      return false;
-    *rect = composition_character_bounds_[index];
-    return true;
-  }
-  bool HasCompositionText() const override {
-    return !composition_character_bounds_.empty();
-  }
-  bool GetCompositionTextRange(gfx::Range* range) const override {
-    if (composition_character_bounds_.empty())
-      return false;
-    *range = gfx::Range(0, composition_character_bounds_.size());
-    return true;
-  }
-
-  ui::TextInputType text_input_type_;
-  ui::TextInputMode text_input_mode_;
-  gfx::Rect caret_bounds_;
-  std::vector<gfx::Rect> composition_character_bounds_;
-  base::string16 inserted_text_;
-  size_t call_count_set_composition_text_;
-  size_t call_count_insert_char_;
-  size_t call_count_insert_text_;
-  bool emulate_pepper_flash_;
-  DISALLOW_COPY_AND_ASSIGN(MockTextInputClient);
-};
-
-class MockInputMethodDelegate : public internal::InputMethodDelegate {
- public:
-  MockInputMethodDelegate() {}
-
-  const std::vector<ui::KeyboardCode>& fabricated_key_events() const {
-    return fabricated_key_events_;
-  }
-  void Reset() {
-    fabricated_key_events_.clear();
-  }
-
- private:
-  ui::EventDispatchDetails DispatchKeyEventPostIME(
-      ui::KeyEvent* event) override {
-    EXPECT_FALSE(event->HasNativeEvent());
-    fabricated_key_events_.push_back(event->key_code());
-    event->SetHandled();
-    return ui::EventDispatchDetails();
-  }
-
-  std::vector<ui::KeyboardCode> fabricated_key_events_;
-  DISALLOW_COPY_AND_ASSIGN(MockInputMethodDelegate);
-};
-
-class MockRemoteInputMethodDelegateWin
-    : public internal::RemoteInputMethodDelegateWin {
- public:
-  MockRemoteInputMethodDelegateWin()
-      : cancel_composition_called_(false),
-        text_input_client_updated_called_(false) {
-  }
-
-  bool cancel_composition_called() const {
-    return cancel_composition_called_;
-  }
-  bool text_input_client_updated_called() const {
-    return text_input_client_updated_called_;
-  }
-  const std::vector<int32_t>& input_scopes() const { return input_scopes_; }
-  const std::vector<gfx::Rect>& composition_character_bounds() const {
-    return composition_character_bounds_;
-  }
-  void Reset() {
-    cancel_composition_called_ = false;
-    text_input_client_updated_called_ = false;
-    input_scopes_.clear();
-    composition_character_bounds_.clear();
-  }
-
- private:
-  void CancelComposition() override { cancel_composition_called_ = true; }
-
-  void OnTextInputClientUpdated(
-      const std::vector<int32_t>& input_scopes,
-      const std::vector<gfx::Rect>& composition_character_bounds) override {
-    text_input_client_updated_called_ = true;
-    input_scopes_ = input_scopes;
-    composition_character_bounds_ = composition_character_bounds;
-  }
-
-  bool cancel_composition_called_;
-  bool text_input_client_updated_called_;
-  std::vector<int32_t> input_scopes_;
-  std::vector<gfx::Rect> composition_character_bounds_;
-  DISALLOW_COPY_AND_ASSIGN(MockRemoteInputMethodDelegateWin);
-};
-
-class MockInputMethodObserver : public InputMethodObserver {
- public:
-  MockInputMethodObserver()
-      : on_text_input_state_changed_(0),
-        on_input_method_destroyed_changed_(0) {
-  }
-  ~MockInputMethodObserver() override {}
-  void Reset() {
-    on_text_input_state_changed_ = 0;
-    on_input_method_destroyed_changed_ = 0;
-  }
-  size_t on_text_input_state_changed() const {
-    return on_text_input_state_changed_;
-  }
-  size_t on_input_method_destroyed_changed() const {
-    return on_input_method_destroyed_changed_;
-  }
-
- private:
-  // Overriden from InputMethodObserver.
-  void OnTextInputTypeChanged(const TextInputClient* client) override {}
-  void OnFocus() override {}
-  void OnBlur() override {}
-  void OnCaretBoundsChanged(const TextInputClient* client) override {}
-  void OnTextInputStateChanged(const TextInputClient* client) override {
-    ++on_text_input_state_changed_;
-  }
-  void OnInputMethodDestroyed(const InputMethod* client) override {
-    ++on_input_method_destroyed_changed_;
-  }
-  void OnShowImeIfNeeded() override {}
-
-  size_t on_text_input_state_changed_;
-  size_t on_input_method_destroyed_changed_;
-  DISALLOW_COPY_AND_ASSIGN(MockInputMethodObserver);
-};
-
-typedef ScopedObserver<InputMethod, InputMethodObserver>
-    InputMethodScopedObserver;
-
-TEST(RemoteInputMethodWinTest, RemoteInputMethodPrivateWin) {
-  InputMethod* other_ptr = static_cast<InputMethod*>(NULL) + 1;
-
-  // Use typed NULL to make EXPECT_NE happy until nullptr becomes available.
-  RemoteInputMethodPrivateWin* kNull =
-      static_cast<RemoteInputMethodPrivateWin*>(NULL);
-  EXPECT_EQ(kNull, RemoteInputMethodPrivateWin::Get(other_ptr));
-
-  MockInputMethodDelegate delegate_;
-  scoped_ptr<InputMethod> input_method(CreateRemoteInputMethodWin(&delegate_));
-  EXPECT_NE(kNull, RemoteInputMethodPrivateWin::Get(input_method.get()));
-
-  InputMethod* dangling_ptr = input_method.get();
-  input_method.reset(NULL);
-  EXPECT_EQ(kNull, RemoteInputMethodPrivateWin::Get(dangling_ptr));
-}
-
-TEST(RemoteInputMethodWinTest, OnInputSourceChanged) {
-  MockInputMethodDelegate delegate_;
-  scoped_ptr<InputMethod> input_method(CreateRemoteInputMethodWin(&delegate_));
-  RemoteInputMethodPrivateWin* private_ptr =
-      RemoteInputMethodPrivateWin::Get(input_method.get());
-  ASSERT_TRUE(private_ptr != NULL);
-
-  private_ptr->OnInputSourceChanged(
-      MAKELANGID(LANG_JAPANESE, SUBLANG_JAPANESE_JAPAN), true);
-  EXPECT_EQ("ja-JP", input_method->GetInputLocale());
-
-  private_ptr->OnInputSourceChanged(
-      MAKELANGID(LANG_ARABIC, SUBLANG_ARABIC_QATAR), true);
-  EXPECT_EQ("ar-QA", input_method->GetInputLocale());
-}
-
-TEST(RemoteInputMethodWinTest, OnCandidatePopupChanged) {
-  MockInputMethodDelegate delegate_;
-  scoped_ptr<InputMethod> input_method(CreateRemoteInputMethodWin(&delegate_));
-  RemoteInputMethodPrivateWin* private_ptr =
-      RemoteInputMethodPrivateWin::Get(input_method.get());
-  ASSERT_TRUE(private_ptr != NULL);
-
-  // Initial value
-  EXPECT_FALSE(input_method->IsCandidatePopupOpen());
-
-  // RemoteInputMethodWin::OnCandidatePopupChanged can be called even when the
-  // focused text input client is NULL.
-  ASSERT_TRUE(input_method->GetTextInputClient() == NULL);
-  private_ptr->OnCandidatePopupChanged(false);
-  private_ptr->OnCandidatePopupChanged(true);
-
-  MockTextInputClient mock_text_input_client;
-  input_method->SetFocusedTextInputClient(&mock_text_input_client);
-
-  mock_text_input_client.Reset();
-
-  private_ptr->OnCandidatePopupChanged(true);
-  EXPECT_TRUE(input_method->IsCandidatePopupOpen());
-
-  private_ptr->OnCandidatePopupChanged(false);
-  EXPECT_FALSE(input_method->IsCandidatePopupOpen());
-}
-
-TEST(RemoteInputMethodWinTest, CancelComposition) {
-  MockInputMethodDelegate delegate_;
-  MockTextInputClient mock_text_input_client;
-  scoped_ptr<InputMethod> input_method(CreateRemoteInputMethodWin(&delegate_));
-
-  // This must not cause a crash.
-  input_method->CancelComposition(&mock_text_input_client);
-
-  RemoteInputMethodPrivateWin* private_ptr =
-      RemoteInputMethodPrivateWin::Get(input_method.get());
-  ASSERT_TRUE(private_ptr != NULL);
-  MockRemoteInputMethodDelegateWin mock_remote_delegate;
-  private_ptr->SetRemoteDelegate(&mock_remote_delegate);
-
-  input_method->CancelComposition(&mock_text_input_client);
-  EXPECT_FALSE(mock_remote_delegate.cancel_composition_called());
-
-  input_method->SetFocusedTextInputClient(&mock_text_input_client);
-  input_method->CancelComposition(&mock_text_input_client);
-  EXPECT_TRUE(mock_remote_delegate.cancel_composition_called());
-}
-
-TEST(RemoteInputMethodWinTest, SetFocusedTextInputClient) {
-  MockInputMethodDelegate delegate_;
-  MockTextInputClient mock_text_input_client;
-  scoped_ptr<InputMethod> input_method(CreateRemoteInputMethodWin(&delegate_));
-
-  mock_text_input_client.set_caret_bounds(gfx::Rect(10, 0, 10, 20));
-  mock_text_input_client.set_text_input_type(ui::TEXT_INPUT_TYPE_URL);
-  input_method->SetFocusedTextInputClient(&mock_text_input_client);
-
-  RemoteInputMethodPrivateWin* private_ptr =
-      RemoteInputMethodPrivateWin::Get(input_method.get());
-  ASSERT_TRUE(private_ptr != NULL);
-  MockRemoteInputMethodDelegateWin mock_remote_delegate;
-  private_ptr->SetRemoteDelegate(&mock_remote_delegate);
-
-  // Initial state must be synced.
-  EXPECT_TRUE(mock_remote_delegate.text_input_client_updated_called());
-  ASSERT_EQ(1u, mock_remote_delegate.composition_character_bounds().size());
-  EXPECT_EQ(gfx::Rect(10, 0, 10, 20),
-            mock_remote_delegate.composition_character_bounds()[0]);
-  ASSERT_EQ(1u, mock_remote_delegate.input_scopes().size());
-  EXPECT_EQ(IS_URL, mock_remote_delegate.input_scopes()[0]);
-
-  // State must be cleared by SetFocusedTextInputClient(NULL).
-  mock_remote_delegate.Reset();
-  input_method->SetFocusedTextInputClient(NULL);
-  EXPECT_TRUE(mock_remote_delegate.text_input_client_updated_called());
-  EXPECT_TRUE(mock_remote_delegate.composition_character_bounds().empty());
-  EXPECT_TRUE(mock_remote_delegate.input_scopes().empty());
-}
-
-TEST(RemoteInputMethodWinTest, DetachTextInputClient) {
-  MockInputMethodDelegate delegate_;
-  MockTextInputClient mock_text_input_client;
-  scoped_ptr<InputMethod> input_method(CreateRemoteInputMethodWin(&delegate_));
-
-  mock_text_input_client.set_caret_bounds(gfx::Rect(10, 0, 10, 20));
-  mock_text_input_client.set_text_input_type(ui::TEXT_INPUT_TYPE_URL);
-  input_method->SetFocusedTextInputClient(&mock_text_input_client);
-
-  RemoteInputMethodPrivateWin* private_ptr =
-      RemoteInputMethodPrivateWin::Get(input_method.get());
-  ASSERT_TRUE(private_ptr != NULL);
-  MockRemoteInputMethodDelegateWin mock_remote_delegate;
-  private_ptr->SetRemoteDelegate(&mock_remote_delegate);
-
-  // Initial state must be synced.
-  EXPECT_TRUE(mock_remote_delegate.text_input_client_updated_called());
-  ASSERT_EQ(1u, mock_remote_delegate.composition_character_bounds().size());
-  EXPECT_EQ(gfx::Rect(10, 0, 10, 20),
-    mock_remote_delegate.composition_character_bounds()[0]);
-  ASSERT_EQ(1u, mock_remote_delegate.input_scopes().size());
-  EXPECT_EQ(IS_URL, mock_remote_delegate.input_scopes()[0]);
-
-  // State must be cleared by DetachTextInputClient
-  mock_remote_delegate.Reset();
-  input_method->DetachTextInputClient(&mock_text_input_client);
-  EXPECT_TRUE(mock_remote_delegate.text_input_client_updated_called());
-  EXPECT_TRUE(mock_remote_delegate.composition_character_bounds().empty());
-  EXPECT_TRUE(mock_remote_delegate.input_scopes().empty());
-}
-
-TEST(RemoteInputMethodWinTest, OnCaretBoundsChanged) {
-  MockInputMethodDelegate delegate_;
-  MockTextInputClient mock_text_input_client;
-  scoped_ptr<InputMethod> input_method(CreateRemoteInputMethodWin(&delegate_));
-
-  // This must not cause a crash.
-  input_method->OnCaretBoundsChanged(&mock_text_input_client);
-
-  mock_text_input_client.set_caret_bounds(gfx::Rect(10, 0, 10, 20));
-  input_method->SetFocusedTextInputClient(&mock_text_input_client);
-
-  RemoteInputMethodPrivateWin* private_ptr =
-      RemoteInputMethodPrivateWin::Get(input_method.get());
-  ASSERT_TRUE(private_ptr != NULL);
-  MockRemoteInputMethodDelegateWin mock_remote_delegate;
-  private_ptr->SetRemoteDelegate(&mock_remote_delegate);
-
-  // Initial state must be synced.
-  EXPECT_TRUE(mock_remote_delegate.text_input_client_updated_called());
-  ASSERT_EQ(1u, mock_remote_delegate.composition_character_bounds().size());
-  EXPECT_EQ(gfx::Rect(10, 0, 10, 20),
-      mock_remote_delegate.composition_character_bounds()[0]);
-
-  // Redundant OnCaretBoundsChanged must be ignored.
-  mock_remote_delegate.Reset();
-  input_method->OnCaretBoundsChanged(&mock_text_input_client);
-  EXPECT_FALSE(mock_remote_delegate.text_input_client_updated_called());
-
-  // Check OnCaretBoundsChanged is handled. (w/o composition)
-  mock_remote_delegate.Reset();
-  mock_text_input_client.Reset();
-  mock_text_input_client.set_caret_bounds(gfx::Rect(10, 20, 30, 40));
-  input_method->OnCaretBoundsChanged(&mock_text_input_client);
-  EXPECT_TRUE(mock_remote_delegate.text_input_client_updated_called());
-  ASSERT_EQ(1u, mock_remote_delegate.composition_character_bounds().size());
-  EXPECT_EQ(gfx::Rect(10, 20, 30, 40),
-      mock_remote_delegate.composition_character_bounds()[0]);
-
-  // Check OnCaretBoundsChanged is handled. (w/ composition)
-  {
-    mock_remote_delegate.Reset();
-    mock_text_input_client.Reset();
-
-    std::vector<gfx::Rect> bounds;
-    bounds.push_back(gfx::Rect(10, 20, 30, 40));
-    bounds.push_back(gfx::Rect(40, 30, 20, 10));
-    mock_text_input_client.set_composition_character_bounds(bounds);
-    input_method->OnCaretBoundsChanged(&mock_text_input_client);
-    EXPECT_TRUE(mock_remote_delegate.text_input_client_updated_called());
-    EXPECT_EQ(bounds, mock_remote_delegate.composition_character_bounds());
-  }
-}
-
-// Test case against crbug.com/328237.
-TEST(RemoteInputMethodWinTest, OnCaretBoundsChangedForPepperFlash) {
-  MockInputMethodDelegate delegate_;
-  MockTextInputClient mock_text_input_client;
-  scoped_ptr<InputMethod> input_method(CreateRemoteInputMethodWin(&delegate_));
-  input_method->SetFocusedTextInputClient(&mock_text_input_client);
-
-  RemoteInputMethodPrivateWin* private_ptr =
-      RemoteInputMethodPrivateWin::Get(input_method.get());
-  ASSERT_TRUE(private_ptr != NULL);
-  MockRemoteInputMethodDelegateWin mock_remote_delegate;
-  private_ptr->SetRemoteDelegate(&mock_remote_delegate);
-
-  mock_remote_delegate.Reset();
-  mock_text_input_client.Reset();
-  mock_text_input_client.set_emulate_pepper_flash(true);
-
-  std::vector<gfx::Rect> caret_bounds;
-  caret_bounds.push_back(gfx::Rect(5, 15, 25, 35));
-  mock_text_input_client.set_caret_bounds(caret_bounds[0]);
-
-  std::vector<gfx::Rect> composition_bounds;
-  composition_bounds.push_back(gfx::Rect(10, 20, 30, 40));
-  composition_bounds.push_back(gfx::Rect(40, 30, 20, 10));
-  mock_text_input_client.set_composition_character_bounds(composition_bounds);
-  input_method->OnCaretBoundsChanged(&mock_text_input_client);
-  EXPECT_TRUE(mock_remote_delegate.text_input_client_updated_called());
-  // The caret bounds must be used when
-  // TextInputClient::GetCompositionCharacterBounds failed.
-  EXPECT_EQ(caret_bounds, mock_remote_delegate.composition_character_bounds());
-}
-
-TEST(RemoteInputMethodWinTest, OnTextInputTypeChanged) {
-  MockInputMethodDelegate delegate_;
-  MockTextInputClient mock_text_input_client;
-  scoped_ptr<InputMethod> input_method(CreateRemoteInputMethodWin(&delegate_));
-
-  // This must not cause a crash.
-  input_method->OnCaretBoundsChanged(&mock_text_input_client);
-
-  mock_text_input_client.set_text_input_type(ui::TEXT_INPUT_TYPE_URL);
-  input_method->SetFocusedTextInputClient(&mock_text_input_client);
-
-  RemoteInputMethodPrivateWin* private_ptr =
-      RemoteInputMethodPrivateWin::Get(input_method.get());
-  ASSERT_TRUE(private_ptr != NULL);
-  MockRemoteInputMethodDelegateWin mock_remote_delegate;
-  private_ptr->SetRemoteDelegate(&mock_remote_delegate);
-
-  // Initial state must be synced.
-  EXPECT_TRUE(mock_remote_delegate.text_input_client_updated_called());
-  ASSERT_EQ(1u, mock_remote_delegate.input_scopes().size());
-  EXPECT_EQ(IS_URL, mock_remote_delegate.input_scopes()[0]);
-
-  // Check TEXT_INPUT_TYPE_NONE is handled.
-  mock_remote_delegate.Reset();
-  mock_text_input_client.Reset();
-  mock_text_input_client.set_text_input_type(ui::TEXT_INPUT_TYPE_NONE);
-  mock_text_input_client.set_text_input_mode(ui::TEXT_INPUT_MODE_KATAKANA);
-  input_method->OnTextInputTypeChanged(&mock_text_input_client);
-  EXPECT_TRUE(mock_remote_delegate.text_input_client_updated_called());
-  EXPECT_TRUE(mock_remote_delegate.input_scopes().empty());
-
-  // Redundant OnTextInputTypeChanged must be ignored.
-  mock_remote_delegate.Reset();
-  input_method->OnTextInputTypeChanged(&mock_text_input_client);
-  EXPECT_FALSE(mock_remote_delegate.text_input_client_updated_called());
-
-  mock_remote_delegate.Reset();
-  mock_text_input_client.Reset();
-  mock_text_input_client.set_caret_bounds(gfx::Rect(10, 20, 30, 40));
-  input_method->OnCaretBoundsChanged(&mock_text_input_client);
-}
-
-TEST(RemoteInputMethodWinTest, DispatchKeyEvent_NativeKeyEvent) {
-  // Basically RemoteInputMethodWin does not handle native keydown event.
-
-  MockInputMethodDelegate delegate_;
-  MockTextInputClient mock_text_input_client;
-  scoped_ptr<InputMethod> input_method(CreateRemoteInputMethodWin(&delegate_));
-
-  const MSG wm_keydown = { NULL, WM_KEYDOWN, ui::VKEY_A };
-  ui::KeyEvent new_keydown(wm_keydown);
-  ui::KeyEvent native_keydown(new_keydown);
-
-  // This must not cause a crash.
-  input_method->DispatchKeyEvent(&native_keydown);
-  EXPECT_FALSE(native_keydown.handled());
-  EXPECT_TRUE(mock_text_input_client.inserted_text().empty());
-  EXPECT_TRUE(delegate_.fabricated_key_events().empty());
-  delegate_.Reset();
-  mock_text_input_client.Reset();
-
-  RemoteInputMethodPrivateWin* private_ptr =
-      RemoteInputMethodPrivateWin::Get(input_method.get());
-  ASSERT_TRUE(private_ptr != NULL);
-  MockRemoteInputMethodDelegateWin mock_remote_delegate;
-  private_ptr->SetRemoteDelegate(&mock_remote_delegate);
-
-  // TextInputClient is not focused yet here.
-  native_keydown = new_keydown;
-  input_method->DispatchKeyEvent(&native_keydown);
-  EXPECT_FALSE(native_keydown.handled());
-  EXPECT_TRUE(mock_text_input_client.inserted_text().empty());
-  EXPECT_TRUE(delegate_.fabricated_key_events().empty());
-  delegate_.Reset();
-  mock_text_input_client.Reset();
-
-  input_method->SetFocusedTextInputClient(&mock_text_input_client);
-
-  // TextInputClient is now focused here.
-  native_keydown = new_keydown;
-  input_method->DispatchKeyEvent(&native_keydown);
-  EXPECT_FALSE(native_keydown.handled());
-  EXPECT_TRUE(mock_text_input_client.inserted_text().empty());
-  EXPECT_TRUE(delegate_.fabricated_key_events().empty());
-  delegate_.Reset();
-  mock_text_input_client.Reset();
-}
-
-TEST(RemoteInputMethodWinTest, DispatchKeyEvent_NativeCharEvent) {
-  // RemoteInputMethodWin handles native char event if possible.
-
-  MockInputMethodDelegate delegate_;
-  MockTextInputClient mock_text_input_client;
-  scoped_ptr<InputMethod> input_method(CreateRemoteInputMethodWin(&delegate_));
-
-  const MSG wm_char = { NULL, WM_CHAR, 'A', 0 };
-  ui::KeyEvent new_char(wm_char);
-  ui::KeyEvent native_char(new_char);
-
-  // This must not cause a crash.
-  input_method->DispatchKeyEvent(&native_char);
-  EXPECT_FALSE(native_char.handled());
-  EXPECT_TRUE(mock_text_input_client.inserted_text().empty());
-  EXPECT_TRUE(delegate_.fabricated_key_events().empty());
-  delegate_.Reset();
-  mock_text_input_client.Reset();
-
-  RemoteInputMethodPrivateWin* private_ptr =
-      RemoteInputMethodPrivateWin::Get(input_method.get());
-  ASSERT_TRUE(private_ptr != NULL);
-  MockRemoteInputMethodDelegateWin mock_remote_delegate;
-  private_ptr->SetRemoteDelegate(&mock_remote_delegate);
-
-  // TextInputClient is not focused yet here.
-  native_char = new_char;
-  input_method->DispatchKeyEvent(&native_char);
-  EXPECT_FALSE(native_char.handled());
-  EXPECT_TRUE(mock_text_input_client.inserted_text().empty());
-  EXPECT_TRUE(delegate_.fabricated_key_events().empty());
-  delegate_.Reset();
-  mock_text_input_client.Reset();
-
-  input_method->SetFocusedTextInputClient(&mock_text_input_client);
-
-  // TextInputClient is now focused here.
-  native_char = new_char;
-  input_method->DispatchKeyEvent(&native_char);
-  EXPECT_TRUE(native_char.handled());
-  EXPECT_EQ(L"A", mock_text_input_client.inserted_text());
-  EXPECT_TRUE(delegate_.fabricated_key_events().empty());
-  delegate_.Reset();
-  mock_text_input_client.Reset();
-}
-
-TEST(RemoteInputMethodWinTest, DispatchKeyEvent_FabricatedKeyDown) {
-  // Fabricated non-char event will be delegated to
-  // InputMethodDelegate::DispatchFabricatedKeyEventPostIME as long as the
-  // delegate is installed.
-
-  MockInputMethodDelegate delegate_;
-  MockTextInputClient mock_text_input_client;
-  scoped_ptr<InputMethod> input_method(CreateRemoteInputMethodWin(&delegate_));
-
-  ui::KeyEvent new_keydown(ui::ET_KEY_PRESSED, ui::VKEY_A, ui::EF_NONE);
-  new_keydown.set_character(L'A');
-  ui::KeyEvent fabricated_keydown(new_keydown);
-
-  // This must not cause a crash.
-  input_method->DispatchKeyEvent(&fabricated_keydown);
-  EXPECT_TRUE(fabricated_keydown.handled());
-  EXPECT_TRUE(mock_text_input_client.inserted_text().empty());
-  ASSERT_EQ(1u, delegate_.fabricated_key_events().size());
-  EXPECT_EQ(L'A', delegate_.fabricated_key_events()[0]);
-  delegate_.Reset();
-  mock_text_input_client.Reset();
-
-  RemoteInputMethodPrivateWin* private_ptr =
-      RemoteInputMethodPrivateWin::Get(input_method.get());
-  ASSERT_TRUE(private_ptr != NULL);
-  MockRemoteInputMethodDelegateWin mock_remote_delegate;
-  private_ptr->SetRemoteDelegate(&mock_remote_delegate);
-
-  // TextInputClient is not focused yet here.
-  fabricated_keydown = new_keydown;
-  input_method->DispatchKeyEvent(&fabricated_keydown);
-  EXPECT_TRUE(fabricated_keydown.handled());
-  EXPECT_TRUE(mock_text_input_client.inserted_text().empty());
-  ASSERT_EQ(1u, delegate_.fabricated_key_events().size());
-  EXPECT_EQ(L'A', delegate_.fabricated_key_events()[0]);
-  delegate_.Reset();
-  mock_text_input_client.Reset();
-
-  input_method->SetFocusedTextInputClient(&mock_text_input_client);
-  // TextInputClient is now focused here.
-  fabricated_keydown = new_keydown;
-  input_method->DispatchKeyEvent(&fabricated_keydown);
-  EXPECT_TRUE(fabricated_keydown.handled());
-  EXPECT_TRUE(mock_text_input_client.inserted_text().empty());
-  ASSERT_EQ(1u, delegate_.fabricated_key_events().size());
-  EXPECT_EQ(L'A', delegate_.fabricated_key_events()[0]);
-  delegate_.Reset();
-  mock_text_input_client.Reset();
-
-  input_method->SetDelegate(NULL);
-  // RemoteInputMethodDelegateWin is no longer set here.
-  fabricated_keydown = new_keydown;
-  input_method->DispatchKeyEvent(&fabricated_keydown);
-  EXPECT_FALSE(fabricated_keydown.handled());
-  EXPECT_TRUE(mock_text_input_client.inserted_text().empty());
-}
-
-TEST(RemoteInputMethodWinTest, DispatchKeyEvent_FabricatedChar) {
-  // Note: RemoteInputMethodWin::DispatchKeyEvent should always return true
-  // for fabricated character events.
-
-  MockInputMethodDelegate delegate_;
-  MockTextInputClient mock_text_input_client;
-  scoped_ptr<InputMethod> input_method(CreateRemoteInputMethodWin(&delegate_));
-
-  ui::KeyEvent new_char(L'A', ui::VKEY_A, ui::EF_NONE);
-  ui::KeyEvent fabricated_char(new_char);
-
-  // This must not cause a crash.
-  input_method->DispatchKeyEvent(&fabricated_char);
-  EXPECT_TRUE(fabricated_char.handled());
-  EXPECT_TRUE(mock_text_input_client.inserted_text().empty());
-  EXPECT_TRUE(delegate_.fabricated_key_events().empty());
-  delegate_.Reset();
-  mock_text_input_client.Reset();
-
-  RemoteInputMethodPrivateWin* private_ptr =
-      RemoteInputMethodPrivateWin::Get(input_method.get());
-  ASSERT_TRUE(private_ptr != NULL);
-  MockRemoteInputMethodDelegateWin mock_remote_delegate;
-  private_ptr->SetRemoteDelegate(&mock_remote_delegate);
-
-  // TextInputClient is not focused yet here.
-  fabricated_char = new_char;
-  input_method->DispatchKeyEvent(&fabricated_char);
-  EXPECT_TRUE(fabricated_char.handled());
-  EXPECT_TRUE(mock_text_input_client.inserted_text().empty());
-  EXPECT_TRUE(delegate_.fabricated_key_events().empty());
-  delegate_.Reset();
-  mock_text_input_client.Reset();
-
-  input_method->SetFocusedTextInputClient(&mock_text_input_client);
-
-  // TextInputClient is now focused here.
-  fabricated_char = new_char;
-  input_method->DispatchKeyEvent(&fabricated_char);
-  EXPECT_TRUE(fabricated_char.handled());
-  EXPECT_EQ(L"A", mock_text_input_client.inserted_text());
-  EXPECT_TRUE(delegate_.fabricated_key_events().empty());
-  delegate_.Reset();
-  mock_text_input_client.Reset();
-}
-
-TEST(RemoteInputMethodWinTest, OnCompositionChanged) {
-  MockInputMethodDelegate delegate_;
-  MockTextInputClient mock_text_input_client;
-  scoped_ptr<InputMethod> input_method(CreateRemoteInputMethodWin(&delegate_));
-
-  RemoteInputMethodPrivateWin* private_ptr =
-      RemoteInputMethodPrivateWin::Get(input_method.get());
-  ASSERT_TRUE(private_ptr != NULL);
-  MockRemoteInputMethodDelegateWin mock_remote_delegate;
-  private_ptr->SetRemoteDelegate(&mock_remote_delegate);
-
-  CompositionText composition_text;
-
-  // TextInputClient is not focused yet here.
-
-  private_ptr->OnCompositionChanged(composition_text);
-  EXPECT_EQ(0u, mock_text_input_client.call_count_set_composition_text());
-  delegate_.Reset();
-  mock_text_input_client.Reset();
-
-  input_method->SetFocusedTextInputClient(&mock_text_input_client);
-
-  // TextInputClient is now focused here.
-
-  private_ptr->OnCompositionChanged(composition_text);
-  EXPECT_EQ(1u, mock_text_input_client.call_count_set_composition_text());
-  delegate_.Reset();
-  mock_text_input_client.Reset();
-}
-
-TEST(RemoteInputMethodWinTest, OnTextCommitted) {
-  MockInputMethodDelegate delegate_;
-  MockTextInputClient mock_text_input_client;
-  scoped_ptr<InputMethod> input_method(CreateRemoteInputMethodWin(&delegate_));
-
-  RemoteInputMethodPrivateWin* private_ptr =
-      RemoteInputMethodPrivateWin::Get(input_method.get());
-  ASSERT_TRUE(private_ptr != NULL);
-  MockRemoteInputMethodDelegateWin mock_remote_delegate;
-  private_ptr->SetRemoteDelegate(&mock_remote_delegate);
-
-  base::string16 committed_text = L"Hello";
-
-  // TextInputClient is not focused yet here.
-
-  mock_text_input_client.set_text_input_type(TEXT_INPUT_TYPE_TEXT);
-  private_ptr->OnTextCommitted(committed_text);
-  EXPECT_EQ(0u, mock_text_input_client.call_count_insert_char());
-  EXPECT_EQ(0u, mock_text_input_client.call_count_insert_text());
-  EXPECT_EQ(L"", mock_text_input_client.inserted_text());
-  delegate_.Reset();
-  mock_text_input_client.Reset();
-
-  input_method->SetFocusedTextInputClient(&mock_text_input_client);
-
-  // TextInputClient is now focused here.
-
-  mock_text_input_client.set_text_input_type(TEXT_INPUT_TYPE_TEXT);
-  private_ptr->OnTextCommitted(committed_text);
-  EXPECT_EQ(0u, mock_text_input_client.call_count_insert_char());
-  EXPECT_EQ(1u, mock_text_input_client.call_count_insert_text());
-  EXPECT_EQ(committed_text, mock_text_input_client.inserted_text());
-  delegate_.Reset();
-  mock_text_input_client.Reset();
-
-  // When TextInputType is TEXT_INPUT_TYPE_NONE, TextInputClient::InsertText
-  // should not be used.
-  mock_text_input_client.set_text_input_type(TEXT_INPUT_TYPE_NONE);
-  private_ptr->OnTextCommitted(committed_text);
-  EXPECT_EQ(committed_text.size(),
-            mock_text_input_client.call_count_insert_char());
-  EXPECT_EQ(0u, mock_text_input_client.call_count_insert_text());
-  EXPECT_EQ(committed_text, mock_text_input_client.inserted_text());
-  delegate_.Reset();
-  mock_text_input_client.Reset();
-}
-
-TEST(RemoteInputMethodWinTest, OnTextInputStateChanged_Observer) {
-  DummyTextInputClient text_input_client;
-  DummyTextInputClient text_input_client_the_other;
-
-  MockInputMethodObserver input_method_observer;
-  MockInputMethodDelegate delegate_;
-  scoped_ptr<InputMethod> input_method(CreateRemoteInputMethodWin(&delegate_));
-  InputMethodScopedObserver scoped_observer(&input_method_observer);
-  scoped_observer.Add(input_method.get());
-
-  input_method->SetFocusedTextInputClient(&text_input_client);
-  ASSERT_EQ(&text_input_client, input_method->GetTextInputClient());
-  EXPECT_EQ(1u, input_method_observer.on_text_input_state_changed());
-  input_method_observer.Reset();
-
-  input_method->SetFocusedTextInputClient(&text_input_client);
-  ASSERT_EQ(&text_input_client, input_method->GetTextInputClient());
-  EXPECT_EQ(0u, input_method_observer.on_text_input_state_changed());
-  input_method_observer.Reset();
-
-  input_method->SetFocusedTextInputClient(&text_input_client_the_other);
-  ASSERT_EQ(&text_input_client_the_other, input_method->GetTextInputClient());
-  EXPECT_EQ(1u, input_method_observer.on_text_input_state_changed());
-  input_method_observer.Reset();
-
-  input_method->DetachTextInputClient(&text_input_client_the_other);
-  ASSERT_TRUE(input_method->GetTextInputClient() == NULL);
-  EXPECT_EQ(1u, input_method_observer.on_text_input_state_changed());
-  input_method_observer.Reset();
-}
-
-TEST(RemoteInputMethodWinTest, OnInputMethodDestroyed_Observer) {
-  DummyTextInputClient text_input_client;
-  DummyTextInputClient text_input_client_the_other;
-
-  MockInputMethodObserver input_method_observer;
-  InputMethodScopedObserver scoped_observer(&input_method_observer);
-
-  MockInputMethodDelegate delegate_;
-  scoped_ptr<InputMethod> input_method(CreateRemoteInputMethodWin(&delegate_));
-  input_method->AddObserver(&input_method_observer);
-
-  EXPECT_EQ(0u, input_method_observer.on_input_method_destroyed_changed());
-  input_method.reset();
-  EXPECT_EQ(1u, input_method_observer.on_input_method_destroyed_changed());
-}
-
-}  // namespace
-}  // namespace ui
diff --git a/ui/base/ime/ui_base_ime.gyp b/ui/base/ime/ui_base_ime.gyp
index 3b5b137..9c3eb388 100644
--- a/ui/base/ime/ui_base_ime.gyp
+++ b/ui/base/ime/ui_base_ime.gyp
@@ -105,9 +105,6 @@
         'linux/linux_input_method_context_factory.h',
         'mock_input_method.cc',
         'mock_input_method.h',
-        'remote_input_method_delegate_win.h',
-        'remote_input_method_win.cc',
-        'remote_input_method_win.h',
         'text_input_client.cc',
         'text_input_client.h',
         'text_input_type.h',
diff --git a/ui/base/ui_base_tests.gyp b/ui/base/ui_base_tests.gyp
index 483b5ae..46ecb92 100644
--- a/ui/base/ui_base_tests.gyp
+++ b/ui/base/ui_base_tests.gyp
@@ -77,7 +77,6 @@
         'ime/composition_text_util_pango_unittest.cc',
         'ime/input_method_base_unittest.cc',
         'ime/input_method_chromeos_unittest.cc',
-        'ime/remote_input_method_win_unittest.cc',
         'ime/win/imm32_manager_unittest.cc',
         'ime/win/tsf_input_scope_unittest.cc',
         'models/list_model_unittest.cc',
diff --git a/ui/compositor/BUILD.gn b/ui/compositor/BUILD.gn
index ff3d4d3f..293a0c9 100644
--- a/ui/compositor/BUILD.gn
+++ b/ui/compositor/BUILD.gn
@@ -48,6 +48,7 @@
     "layer_delegate.h",
     "layer_owner.cc",
     "layer_owner.h",
+    "layer_threaded_animation_delegate.h",
     "layer_tree_owner.cc",
     "layer_tree_owner.h",
     "layer_type.h",
diff --git a/ui/compositor/compositor.gyp b/ui/compositor/compositor.gyp
index 4ab5b0c..0e65659 100644
--- a/ui/compositor/compositor.gyp
+++ b/ui/compositor/compositor.gyp
@@ -66,6 +66,7 @@
         'layer_delegate.h',
         'layer_owner.cc',
         'layer_owner.h',
+        'layer_threaded_animation_delegate.h',
         'layer_tree_owner.cc',
         'layer_tree_owner.h',
         'layer_type.h',
diff --git a/ui/compositor/layer.cc b/ui/compositor/layer.cc
index e5569d0f..89a1d262 100644
--- a/ui/compositor/layer.cc
+++ b/ui/compositor/layer.cc
@@ -529,6 +529,13 @@
   SetLayerBackgroundFilters();
 }
 
+bool Layer::HasPendingThreadedAnimationsForTesting() const {
+  if (UILayerSettings().use_compositor_animation_timelines)
+    return animator_->HasPendingThreadedAnimationsForTesting();
+  else
+    return !pending_threaded_animations_.empty();
+}
+
 void Layer::SwitchCCLayerForTest() {
   scoped_refptr<cc::Layer> new_layer =
       cc::PictureLayer::Create(UILayerSettings(), this);
@@ -973,15 +980,11 @@
 
 void Layer::AddThreadedAnimation(scoped_ptr<cc::Animation> animation) {
   DCHECK(cc_layer_);
+  DCHECK(!UILayerSettings().use_compositor_animation_timelines);
   // Until this layer has a compositor (and hence cc_layer_ has a
   // LayerTreeHost), addAnimation will fail.
   if (GetCompositor()) {
-    if (UILayerSettings().use_compositor_animation_timelines) {
-      DCHECK(animator_);
-      animator_->AddThreadedAnimation(std::move(animation));
-    } else {
-      cc_layer_->AddAnimation(std::move(animation));
-    }
+    cc_layer_->AddAnimation(std::move(animation));
   } else {
     pending_threaded_animations_.push_back(std::move(animation));
   }
@@ -989,13 +992,9 @@
 
 void Layer::RemoveThreadedAnimation(int animation_id) {
   DCHECK(cc_layer_);
+  DCHECK(!UILayerSettings().use_compositor_animation_timelines);
   if (pending_threaded_animations_.size() == 0) {
-    if (UILayerSettings().use_compositor_animation_timelines) {
-      DCHECK(animator_);
-      animator_->RemoveThreadedAnimation(animation_id);
-    } else {
-      cc_layer_->RemoveAnimation(animation_id);
-    }
+    cc_layer_->RemoveAnimation(animation_id);
     return;
   }
 
@@ -1018,15 +1017,23 @@
   return cc_layer_;
 }
 
-void Layer::SendPendingThreadedAnimations() {
-  for (auto& animation : pending_threaded_animations_) {
-    if (UILayerSettings().use_compositor_animation_timelines) {
-      DCHECK(animator_);
-      animator_->AddThreadedAnimation(std::move(animation));
-    } else {
-      cc_layer_->AddAnimation(std::move(animation));
-    }
+LayerThreadedAnimationDelegate* Layer::GetThreadedAnimationDelegate() {
+  if (UILayerSettings().use_compositor_animation_timelines) {
+    DCHECK(animator_);
+    return animator_.get();
+  } else {
+    return this;
   }
+}
+
+void Layer::SendPendingThreadedAnimations() {
+  if (UILayerSettings().use_compositor_animation_timelines) {
+    DCHECK(pending_threaded_animations_.empty());
+    return;
+  }
+
+  for (auto& animation : pending_threaded_animations_)
+    cc_layer_->AddAnimation(std::move(animation));
   pending_threaded_animations_.clear();
 
   for (auto* child : children_)
diff --git a/ui/compositor/layer.h b/ui/compositor/layer.h
index 689cf39a..f573d8e3 100644
--- a/ui/compositor/layer.h
+++ b/ui/compositor/layer.h
@@ -27,6 +27,7 @@
 #include "ui/compositor/compositor.h"
 #include "ui/compositor/layer_animation_delegate.h"
 #include "ui/compositor/layer_delegate.h"
+#include "ui/compositor/layer_threaded_animation_delegate.h"
 #include "ui/compositor/layer_type.h"
 #include "ui/gfx/geometry/rect.h"
 #include "ui/gfx/image/image_skia.h"
@@ -67,6 +68,7 @@
 // NULL, but the children are not deleted.
 class COMPOSITOR_EXPORT Layer
     : public LayerAnimationDelegate,
+      public LayerThreadedAnimationDelegate,
       NON_EXPORTED_BASE(public cc::ContentLayerClient),
       NON_EXPORTED_BASE(public cc::TextureLayerClient),
       NON_EXPORTED_BASE(public cc::LayerClient) {
@@ -373,9 +375,7 @@
       cc::Layer* layer) override;
 
   // Whether this layer has animations waiting to get sent to its cc::Layer.
-  bool HasPendingThreadedAnimations() {
-    return pending_threaded_animations_.size() != 0;
-  }
+  bool HasPendingThreadedAnimationsForTesting() const;
 
   // Triggers a call to SwitchToLayer.
   void SwitchCCLayerForTest();
@@ -409,10 +409,13 @@
   float GetGrayscaleForAnimation() const override;
   SkColor GetColorForAnimation() const override;
   float GetDeviceScaleFactor() const override;
+  cc::Layer* GetCcLayer() const override;
+  LayerThreadedAnimationDelegate* GetThreadedAnimationDelegate() override;
+  LayerAnimatorCollection* GetLayerAnimatorCollection() override;
+
+  // Implementation of LayerThreadedAnimationDelegate.
   void AddThreadedAnimation(scoped_ptr<cc::Animation> animation) override;
   void RemoveThreadedAnimation(int animation_id) override;
-  LayerAnimatorCollection* GetLayerAnimatorCollection() override;
-  cc::Layer* GetCcLayer() const override;
 
   // Creates a corresponding composited layer for |type_|.
   void CreateCcLayer();
diff --git a/ui/compositor/layer_animation_delegate.h b/ui/compositor/layer_animation_delegate.h
index e1ec62451..b1db0b30 100644
--- a/ui/compositor/layer_animation_delegate.h
+++ b/ui/compositor/layer_animation_delegate.h
@@ -5,8 +5,6 @@
 #ifndef UI_COMPOSITOR_LAYER_ANIMATION_DELEGATE_H_
 #define UI_COMPOSITOR_LAYER_ANIMATION_DELEGATE_H_
 
-#include "base/memory/scoped_ptr.h"
-#include "cc/animation/animation.h"
 #include "third_party/skia/include/core/SkColor.h"
 #include "ui/compositor/compositor_export.h"
 #include "ui/gfx/geometry/rect.h"
@@ -19,6 +17,7 @@
 namespace ui {
 
 class LayerAnimatorCollection;
+class LayerThreadedAnimationDelegate;
 
 // Layer animations interact with the layers using this interface.
 class COMPOSITOR_EXPORT LayerAnimationDelegate {
@@ -39,14 +38,9 @@
   virtual float GetGrayscaleForAnimation() const = 0;
   virtual SkColor GetColorForAnimation() const = 0;
   virtual float GetDeviceScaleFactor() const = 0;
-
-  // TODO(loyso): Extract these 3 methods as a separate
-  // LayerThreadedAnimationDelegate.
-  virtual void AddThreadedAnimation(scoped_ptr<cc::Animation> animation) = 0;
-  virtual void RemoveThreadedAnimation(int animation_id) = 0;
   virtual cc::Layer* GetCcLayer() const = 0;
-
   virtual LayerAnimatorCollection* GetLayerAnimatorCollection() = 0;
+  virtual LayerThreadedAnimationDelegate* GetThreadedAnimationDelegate() = 0;
 
  protected:
   virtual ~LayerAnimationDelegate() {}
diff --git a/ui/compositor/layer_animation_element.cc b/ui/compositor/layer_animation_element.cc
index 5e0f558..29aa7fa 100644
--- a/ui/compositor/layer_animation_element.cc
+++ b/ui/compositor/layer_animation_element.cc
@@ -344,7 +344,10 @@
       return false;
 
     if (Started() && IsThreaded()) {
-      delegate->RemoveThreadedAnimation(animation_id());
+      LayerThreadedAnimationDelegate* threaded =
+          delegate->GetThreadedAnimationDelegate();
+      DCHECK(threaded);
+      threaded->RemoveThreadedAnimation(animation_id());
     }
 
     OnEnd(delegate);
@@ -353,7 +356,10 @@
 
   void OnAbort(LayerAnimationDelegate* delegate) override {
     if (delegate && Started() && IsThreaded()) {
-      delegate->RemoveThreadedAnimation(animation_id());
+      LayerThreadedAnimationDelegate* threaded =
+          delegate->GetThreadedAnimationDelegate();
+      DCHECK(threaded);
+      threaded->RemoveThreadedAnimation(animation_id());
     }
   }
 
@@ -366,7 +372,11 @@
     set_effective_start_time(base::TimeTicks());
     scoped_ptr<cc::Animation> animation = CreateCCAnimation();
     animation->set_needs_synchronized_start_time(true);
-    delegate->AddThreadedAnimation(std::move(animation));
+
+    LayerThreadedAnimationDelegate* threaded =
+        delegate->GetThreadedAnimationDelegate();
+    DCHECK(threaded);
+    threaded->AddThreadedAnimation(std::move(animation));
   }
 
   virtual void OnEnd(LayerAnimationDelegate* delegate) = 0;
diff --git a/ui/compositor/layer_animator.cc b/ui/compositor/layer_animator.cc
index 60a37f6..08d8e11 100644
--- a/ui/compositor/layer_animator.cc
+++ b/ui/compositor/layer_animator.cc
@@ -211,6 +211,11 @@
   animation_player_->RemoveAnimation(animation_id);
 }
 
+bool LayerAnimator::HasPendingThreadedAnimationsForTesting() const {
+  DCHECK(animation_player_);
+  return animation_player_->has_pending_animations_for_testing();
+}
+
 void LayerAnimator::StartAnimation(LayerAnimationSequence* animation) {
   scoped_refptr<LayerAnimator> retain(this);
   OnScheduled(animation);
diff --git a/ui/compositor/layer_animator.h b/ui/compositor/layer_animator.h
index a0f5e92..6fc1878 100644
--- a/ui/compositor/layer_animator.h
+++ b/ui/compositor/layer_animator.h
@@ -18,6 +18,7 @@
 #include "cc/animation/layer_animation_event_observer.h"
 #include "ui/compositor/compositor_export.h"
 #include "ui/compositor/layer_animation_element.h"
+#include "ui/compositor/layer_threaded_animation_delegate.h"
 #include "ui/gfx/animation/tween.h"
 
 namespace cc {
@@ -53,6 +54,7 @@
 // must guarantee that |this| is valid.
 class COMPOSITOR_EXPORT LayerAnimator
     : public base::RefCounted<LayerAnimator>,
+      public LayerThreadedAnimationDelegate,
       NON_EXPORTED_BASE(public cc::LayerAnimationEventObserver) {
  public:
   enum PreemptionStrategy {
@@ -117,10 +119,8 @@
   // Detach AnimationPlayer from Layer and AnimationTimeline
   void ResetCompositor(Compositor* compositor);
 
-  // TODO(loyso): Rework it as an implementation for
-  // LayerThreadedAnimationDelegate and make it private.
-  void AddThreadedAnimation(scoped_ptr<cc::Animation> animation);
-  void RemoveThreadedAnimation(int animation_id);
+  // Whether this animator has animations waiting to get sent to cc::LAC.
+  bool HasPendingThreadedAnimationsForTesting() const;
 
   // Sets the animation preemption strategy. This determines the behaviour if
   // a property is set during an animation. The default is
@@ -339,6 +339,10 @@
   // LayerAnimationEventObserver
   void OnAnimationStarted(const cc::AnimationEvent& event) override;
 
+  // Implementation of LayerThreadedAnimationDelegate.
+  void AddThreadedAnimation(scoped_ptr<cc::Animation> animation) override;
+  void RemoveThreadedAnimation(int animation_id) override;
+
   void AttachLayerToAnimationPlayer(int layer_id);
   void DetachLayerFromAnimationPlayer();
 
diff --git a/ui/compositor/layer_threaded_animation_delegate.h b/ui/compositor/layer_threaded_animation_delegate.h
new file mode 100644
index 0000000..b921077e
--- /dev/null
+++ b/ui/compositor/layer_threaded_animation_delegate.h
@@ -0,0 +1,26 @@
+// Copyright (c) 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 UI_COMPOSITOR_LAYER_THREADED_ANIMATION_DELEGATE_H_
+#define UI_COMPOSITOR_LAYER_THREADED_ANIMATION_DELEGATE_H_
+
+#include "base/memory/scoped_ptr.h"
+#include "cc/animation/animation.h"
+#include "ui/compositor/compositor_export.h"
+
+namespace ui {
+
+// Attach CC animations using this interface.
+class COMPOSITOR_EXPORT LayerThreadedAnimationDelegate {
+ public:
+  virtual void AddThreadedAnimation(scoped_ptr<cc::Animation> animation) = 0;
+  virtual void RemoveThreadedAnimation(int animation_id) = 0;
+
+ protected:
+  virtual ~LayerThreadedAnimationDelegate() {}
+};
+
+}  // namespace ui
+
+#endif  // UI_COMPOSITOR_LAYER_THREADED_ANIMATION_DELEGATE_H_
diff --git a/ui/compositor/layer_unittest.cc b/ui/compositor/layer_unittest.cc
index 70581b6..d9f5a7a0 100644
--- a/ui/compositor/layer_unittest.cc
+++ b/ui/compositor/layer_unittest.cc
@@ -1605,41 +1605,41 @@
   l1->SetAnimator(LayerAnimator::CreateImplicitAnimator());
   l2->SetAnimator(LayerAnimator::CreateImplicitAnimator());
 
-  EXPECT_FALSE(l1->HasPendingThreadedAnimations());
+  EXPECT_FALSE(l1->HasPendingThreadedAnimationsForTesting());
 
   // Trigger a threaded animation.
   l1->SetOpacity(0.5f);
 
-  EXPECT_TRUE(l1->HasPendingThreadedAnimations());
+  EXPECT_TRUE(l1->HasPendingThreadedAnimationsForTesting());
 
   // Ensure we can remove a pending threaded animation.
   l1->GetAnimator()->StopAnimating();
 
-  EXPECT_FALSE(l1->HasPendingThreadedAnimations());
+  EXPECT_FALSE(l1->HasPendingThreadedAnimationsForTesting());
 
   // Trigger another threaded animation.
   l1->SetOpacity(0.2f);
 
-  EXPECT_TRUE(l1->HasPendingThreadedAnimations());
+  EXPECT_TRUE(l1->HasPendingThreadedAnimationsForTesting());
 
   root->Add(l1.get());
   GetCompositor()->SetRootLayer(root.get());
 
   // Now that l1 is part of a tree, it should have dispatched the pending
   // animation.
-  EXPECT_FALSE(l1->HasPendingThreadedAnimations());
+  EXPECT_FALSE(l1->HasPendingThreadedAnimationsForTesting());
 
   // Ensure that l1 no longer holds on to animations.
   l1->SetOpacity(0.1f);
-  EXPECT_FALSE(l1->HasPendingThreadedAnimations());
+  EXPECT_FALSE(l1->HasPendingThreadedAnimationsForTesting());
 
   // Ensure that adding a layer to an existing tree causes its pending
   // animations to get dispatched.
   l2->SetOpacity(0.5f);
-  EXPECT_TRUE(l2->HasPendingThreadedAnimations());
+  EXPECT_TRUE(l2->HasPendingThreadedAnimationsForTesting());
 
   l1->Add(l2.get());
-  EXPECT_FALSE(l2->HasPendingThreadedAnimations());
+  EXPECT_FALSE(l2->HasPendingThreadedAnimationsForTesting());
 }
 
 // Tests that in-progress threaded animations complete when a Layer's
diff --git a/ui/compositor/test/test_layer_animation_delegate.cc b/ui/compositor/test/test_layer_animation_delegate.cc
index 140e81ea..980e3978 100644
--- a/ui/compositor/test/test_layer_animation_delegate.cc
+++ b/ui/compositor/test/test_layer_animation_delegate.cc
@@ -7,6 +7,10 @@
 
 namespace ui {
 
+TestLayerThreadedAnimationDelegate::TestLayerThreadedAnimationDelegate() {}
+
+TestLayerThreadedAnimationDelegate::~TestLayerThreadedAnimationDelegate() {}
+
 TestLayerAnimationDelegate::TestLayerAnimationDelegate()
     : opacity_(1.0f),
       visibility_(true),
@@ -94,13 +98,6 @@
   return 1.0f;
 }
 
-void TestLayerAnimationDelegate::AddThreadedAnimation(
-      scoped_ptr<cc::Animation> animation) {
-}
-
-void TestLayerAnimationDelegate::RemoveThreadedAnimation(int animation_id) {
-}
-
 LayerAnimatorCollection*
 TestLayerAnimationDelegate::GetLayerAnimatorCollection() {
   return NULL;
@@ -110,8 +107,19 @@
   return cc_layer_.get();
 }
 
+LayerThreadedAnimationDelegate*
+TestLayerAnimationDelegate::GetThreadedAnimationDelegate() {
+  return &threaded_delegate_;
+}
+
 void TestLayerAnimationDelegate::CreateCcLayer() {
   cc_layer_ = cc::Layer::Create(ui::Layer::UILayerSettings());
 }
 
+void TestLayerThreadedAnimationDelegate::AddThreadedAnimation(
+    scoped_ptr<cc::Animation> animation) {}
+
+void TestLayerThreadedAnimationDelegate::RemoveThreadedAnimation(
+    int animation_id) {}
+
 }  // namespace ui
diff --git a/ui/compositor/test/test_layer_animation_delegate.h b/ui/compositor/test/test_layer_animation_delegate.h
index f06f054..ef4215835 100644
--- a/ui/compositor/test/test_layer_animation_delegate.h
+++ b/ui/compositor/test/test_layer_animation_delegate.h
@@ -8,11 +8,23 @@
 #include "base/compiler_specific.h"
 #include "cc/layers/layer.h"
 #include "ui/compositor/layer_animation_delegate.h"
+#include "ui/compositor/layer_threaded_animation_delegate.h"
 #include "ui/gfx/geometry/rect.h"
 #include "ui/gfx/transform.h"
 
 namespace ui {
 
+class TestLayerThreadedAnimationDelegate
+    : public LayerThreadedAnimationDelegate {
+ public:
+  TestLayerThreadedAnimationDelegate();
+  ~TestLayerThreadedAnimationDelegate() override;
+
+  // Implementation of LayerThreadedAnimationDelegate
+  void AddThreadedAnimation(scoped_ptr<cc::Animation> animation) override;
+  void RemoveThreadedAnimation(int animation_id) override;
+};
+
 class TestLayerAnimationDelegate : public LayerAnimationDelegate {
  public:
   TestLayerAnimationDelegate();
@@ -36,14 +48,15 @@
   float GetGrayscaleForAnimation() const override;
   SkColor GetColorForAnimation() const override;
   float GetDeviceScaleFactor() const override;
-  void AddThreadedAnimation(scoped_ptr<cc::Animation> animation) override;
-  void RemoveThreadedAnimation(int animation_id) override;
   LayerAnimatorCollection* GetLayerAnimatorCollection() override;
   cc::Layer* GetCcLayer() const override;
+  LayerThreadedAnimationDelegate* GetThreadedAnimationDelegate() override;
 
  private:
   void CreateCcLayer();
 
+  TestLayerThreadedAnimationDelegate threaded_delegate_;
+
   gfx::Rect bounds_;
   gfx::Transform transform_;
   float opacity_;
diff --git a/ui/events/blink/input_handler_proxy.cc b/ui/events/blink/input_handler_proxy.cc
index b0b76596..8511af6 100644
--- a/ui/events/blink/input_handler_proxy.cc
+++ b/ui/events/blink/input_handler_proxy.cc
@@ -359,6 +359,51 @@
   return DID_NOT_HANDLE;
 }
 
+void RecordMainThreadScrollingReasons(
+    WebInputEvent::Type type,
+    cc::InputHandler::MainThreadScrollingReason reasons) {
+  static const char* kGestureHistogramName =
+      "Renderer4.MainThreadGestureScrollReason";
+  static const char* kWheelHistogramName =
+      "Renderer4.MainThreadWheelScrollReason";
+
+  DCHECK(type == WebInputEvent::GestureScrollBegin ||
+         type == WebInputEvent::MouseWheel);
+
+  if (type != WebInputEvent::GestureScrollBegin &&
+      type != WebInputEvent::MouseWheel) {
+    return;
+  }
+
+  if (reasons == cc::InputHandler::NOT_SCROLLING_ON_MAIN) {
+    if (type == WebInputEvent::GestureScrollBegin) {
+      UMA_HISTOGRAM_ENUMERATION(
+          kGestureHistogramName, cc::InputHandler::NOT_SCROLLING_ON_MAIN,
+          cc::InputHandler::MainThreadScrollingReasonCount);
+    } else {
+      UMA_HISTOGRAM_ENUMERATION(
+          kWheelHistogramName, cc::InputHandler::NOT_SCROLLING_ON_MAIN,
+          cc::InputHandler::MainThreadScrollingReasonCount);
+    }
+  }
+
+  for (int i = 0; i < cc::InputHandler::MainThreadScrollingReasonCount - 1;
+       ++i) {
+    unsigned val = 1 << i;
+    if (reasons & val) {
+      if (type == WebInputEvent::GestureScrollBegin) {
+        UMA_HISTOGRAM_ENUMERATION(
+            kGestureHistogramName, i + 1,
+            cc::InputHandler::MainThreadScrollingReasonCount);
+      } else {
+        UMA_HISTOGRAM_ENUMERATION(
+            kWheelHistogramName, i + 1,
+            cc::InputHandler::MainThreadScrollingReasonCount);
+      }
+    }
+  }
+}
+
 bool InputHandlerProxy::ShouldAnimate(
     const blink::WebMouseWheelEvent& event) const {
 #if defined(OS_MACOSX)
@@ -396,8 +441,12 @@
     cc::InputHandler::ScrollStatus scroll_status =
         input_handler_->ScrollAnimated(gfx::Point(wheel_event.x, wheel_event.y),
                                        scroll_delta);
-    switch (scroll_status) {
-      case cc::InputHandler::SCROLL_STARTED:
+
+    RecordMainThreadScrollingReasons(
+        wheel_event.type, scroll_status.main_thread_scrolling_reasons);
+
+    switch (scroll_status.thread) {
+      case cc::InputHandler::SCROLL_ON_IMPL_THREAD:
         result = DID_HANDLE;
         break;
       case cc::InputHandler::SCROLL_IGNORED:
@@ -410,11 +459,14 @@
   } else {
     cc::ScrollState scroll_state_begin(0, 0, wheel_event.x, wheel_event.y, 0, 0,
                                        true, false, false);
-    cc::InputHandler::ScrollStatus scroll_status =
-        input_handler_->ScrollBegin(&scroll_state_begin,
-                                    cc::InputHandler::WHEEL);
-    switch (scroll_status) {
-      case cc::InputHandler::SCROLL_STARTED: {
+    cc::InputHandler::ScrollStatus scroll_status = input_handler_->ScrollBegin(
+        &scroll_state_begin, cc::InputHandler::WHEEL);
+
+    RecordMainThreadScrollingReasons(
+        wheel_event.type, scroll_status.main_thread_scrolling_reasons);
+
+    switch (scroll_status.thread) {
+      case cc::InputHandler::SCROLL_ON_IMPL_THREAD: {
         TRACE_EVENT_INSTANT2("input",
                              "InputHandlerProxy::handle_input wheel scroll",
                              TRACE_EVENT_SCOPE_THREAD, "deltaX",
@@ -487,10 +539,14 @@
         input_handler_->ScrollBegin(&scroll_state, cc::InputHandler::GESTURE);
   }
   UMA_HISTOGRAM_ENUMERATION("Renderer4.CompositorScrollHitTestResult",
-                            scroll_status,
+                            scroll_status.thread,
                             cc::InputHandler::ScrollStatusCount);
-  switch (scroll_status) {
-    case cc::InputHandler::SCROLL_STARTED:
+
+  RecordMainThreadScrollingReasons(gesture_event.type,
+                                   scroll_status.main_thread_scrolling_reasons);
+
+  switch (scroll_status.thread) {
+    case cc::InputHandler::SCROLL_ON_IMPL_THREAD:
       TRACE_EVENT_INSTANT0("input",
                            "InputHandlerProxy::handle_input gesture scroll",
                            TRACE_EVENT_SCOPE_THREAD);
@@ -542,8 +598,9 @@
 InputHandlerProxy::EventDisposition InputHandlerProxy::HandleGestureFlingStart(
     const WebGestureEvent& gesture_event) {
   cc::ScrollState scroll_state = CreateScrollStateForGesture(gesture_event);
-  cc::InputHandler::ScrollStatus scroll_status =
-      cc::InputHandler::SCROLL_ON_MAIN_THREAD;
+  cc::InputHandler::ScrollStatus scroll_status;
+  scroll_status.main_thread_scrolling_reasons =
+      cc::InputHandler::NOT_SCROLLING_ON_MAIN;
   switch (gesture_event.sourceDevice) {
   case blink::WebGestureDeviceTouchpad:
     if (gesture_event.data.flingStart.targetViewport) {
@@ -555,10 +612,13 @@
     }
     break;
   case blink::WebGestureDeviceTouchscreen:
-    if (!gesture_scroll_on_impl_thread_)
-      scroll_status = cc::InputHandler::SCROLL_ON_MAIN_THREAD;
-    else
+    if (!gesture_scroll_on_impl_thread_) {
+      scroll_status.thread = cc::InputHandler::SCROLL_ON_MAIN_THREAD;
+      scroll_status.main_thread_scrolling_reasons =
+          cc::InputHandler::CONTINUING_MAIN_THREAD_SCROLL;
+    } else {
       scroll_status = input_handler_->FlingScrollBegin();
+    }
     break;
   case blink::WebGestureDeviceUninitialized:
     NOTREACHED();
@@ -569,8 +629,8 @@
   expect_scroll_update_end_ = false;
 #endif
 
-  switch (scroll_status) {
-    case cc::InputHandler::SCROLL_STARTED: {
+  switch (scroll_status.thread) {
+    case cc::InputHandler::SCROLL_ON_IMPL_THREAD: {
       if (gesture_event.sourceDevice == blink::WebGestureDeviceTouchpad) {
         scroll_state.set_is_ending(true);
         input_handler_->ScrollEnd(&scroll_state);
diff --git a/ui/events/blink/input_handler_proxy_unittest.cc b/ui/events/blink/input_handler_proxy_unittest.cc
index ccf24f4..3beb7e86 100644
--- a/ui/events/blink/input_handler_proxy_unittest.cc
+++ b/ui/events/blink/input_handler_proxy_unittest.cc
@@ -242,6 +242,18 @@
   return point;
 }
 
+const cc::InputHandler::ScrollStatus kImplThreadScrollState(
+    cc::InputHandler::SCROLL_ON_IMPL_THREAD,
+    cc::InputHandler::NOT_SCROLLING_ON_MAIN);
+
+const cc::InputHandler::ScrollStatus kMainThreadScrollState(
+    cc::InputHandler::SCROLL_ON_MAIN_THREAD,
+    cc::InputHandler::EVENT_HANDLERS);
+
+const cc::InputHandler::ScrollStatus kScrollIgnoredScrollState(
+    cc::InputHandler::SCROLL_IGNORED,
+    cc::InputHandler::NOT_SCROLLABLE);
+
 }  // namespace
 
 class InputHandlerProxyTest
@@ -321,7 +333,7 @@
     VERIFY_AND_RESET_MOCKS();
 
     EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_))
-        .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED));
+        .WillOnce(testing::Return(kImplThreadScrollState));
     gesture_.type = WebInputEvent::GestureScrollBegin;
     gesture_.sourceDevice = source_device;
     EXPECT_EQ(expected_disposition_,
@@ -330,7 +342,7 @@
     VERIFY_AND_RESET_MOCKS();
 
     EXPECT_CALL(mock_input_handler_, FlingScrollBegin())
-        .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED));
+        .WillOnce(testing::Return(kImplThreadScrollState));
     EXPECT_SET_NEEDS_ANIMATE_INPUT(1);
 
     gesture_ =
@@ -404,7 +416,7 @@
   // Smooth scroll because hasPreciseScrollingDeltas is set to false.
   wheel.hasPreciseScrollingDeltas = false;
   EXPECT_CALL(mock_input_handler_, ScrollAnimated(::testing::_, ::testing::_))
-      .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED));
+      .WillOnce(testing::Return(kImplThreadScrollState));
   EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(wheel));
 
   VERIFY_AND_RESET_MOCKS();
@@ -412,7 +424,7 @@
   // No smooth scroll because hasPreciseScrollingDeltas is set to true.
   wheel.hasPreciseScrollingDeltas = true;
   EXPECT_CALL(mock_input_handler_, ScrollBegin(::testing::_, ::testing::_))
-      .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED));
+      .WillOnce(testing::Return(kImplThreadScrollState));
   EXPECT_CALL(mock_input_handler_, ScrollBy(::testing::_))
       .WillOnce(testing::Return(scroll_result_did_scroll_));
   EXPECT_CALL(mock_input_handler_, ScrollEnd(testing::_));
@@ -433,7 +445,7 @@
   wheel.type = WebInputEvent::MouseWheel;
 
   EXPECT_CALL(mock_input_handler_, ScrollAnimated(testing::_, testing::_))
-      .WillOnce(testing::Return(cc::InputHandler::SCROLL_IGNORED));
+      .WillOnce(testing::Return(kScrollIgnoredScrollState));
 
   EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(wheel));
   VERIFY_AND_RESET_MOCKS();
@@ -445,7 +457,7 @@
   VERIFY_AND_RESET_MOCKS();
 
   EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_))
-      .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED));
+      .WillOnce(testing::Return(kImplThreadScrollState));
 
   gesture_.type = WebInputEvent::GestureScrollBegin;
   EXPECT_EQ(expected_disposition_,input_handler_->HandleInputEvent(gesture_));
@@ -492,7 +504,7 @@
   VERIFY_AND_RESET_MOCKS();
 
   EXPECT_CALL(mock_input_handler_, ScrollBegin(::testing::_, ::testing::_))
-      .WillOnce(testing::Return(cc::InputHandler::SCROLL_ON_MAIN_THREAD));
+      .WillOnce(testing::Return(kMainThreadScrollState));
 
   gesture_.type = WebInputEvent::GestureScrollBegin;
   EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_));
@@ -524,7 +536,7 @@
   VERIFY_AND_RESET_MOCKS();
 
   EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_))
-      .WillOnce(testing::Return(cc::InputHandler::SCROLL_IGNORED));
+      .WillOnce(testing::Return(kScrollIgnoredScrollState));
 
   gesture_.type = WebInputEvent::GestureScrollBegin;
   EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_));
@@ -544,7 +556,7 @@
   VERIFY_AND_RESET_MOCKS();
 
   EXPECT_CALL(mock_input_handler_, RootScrollBegin(testing::_, testing::_))
-      .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED));
+      .WillOnce(testing::Return(kImplThreadScrollState));
 
   gesture_.type = WebInputEvent::GestureScrollBegin;
   gesture_.data.scrollBegin.targetViewport = true;
@@ -640,7 +652,7 @@
   VERIFY_AND_RESET_MOCKS();
 
   EXPECT_CALL(mock_input_handler_, ScrollBegin(::testing::_, ::testing::_))
-      .WillOnce(testing::Return(cc::InputHandler::SCROLL_ON_MAIN_THREAD));
+      .WillOnce(testing::Return(kMainThreadScrollState));
 
   gesture_.type = WebInputEvent::GestureScrollBegin;
   EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_));
@@ -717,7 +729,7 @@
   VERIFY_AND_RESET_MOCKS();
 
   EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_))
-      .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED));
+      .WillOnce(testing::Return(kImplThreadScrollState));
   EXPECT_CALL(mock_input_handler_, ScrollEnd(testing::_));
   EXPECT_SET_NEEDS_ANIMATE_INPUT(1);
 
@@ -740,7 +752,7 @@
   VERIFY_AND_RESET_MOCKS();
 
   EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_))
-      .WillOnce(testing::Return(cc::InputHandler::SCROLL_ON_MAIN_THREAD));
+      .WillOnce(testing::Return(kMainThreadScrollState));
 
   gesture_.type = WebInputEvent::GestureFlingStart;
   gesture_.sourceDevice = blink::WebGestureDeviceTouchpad;
@@ -764,7 +776,7 @@
   VERIFY_AND_RESET_MOCKS();
 
   EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_))
-      .WillOnce(testing::Return(cc::InputHandler::SCROLL_IGNORED));
+      .WillOnce(testing::Return(kScrollIgnoredScrollState));
 
   gesture_.type = WebInputEvent::GestureFlingStart;
   gesture_.sourceDevice = blink::WebGestureDeviceTouchpad;
@@ -801,7 +813,7 @@
                          modifiers);
   EXPECT_SET_NEEDS_ANIMATE_INPUT(1);
   EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_))
-      .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED));
+      .WillOnce(testing::Return(kImplThreadScrollState));
   EXPECT_CALL(mock_input_handler_, ScrollEnd(testing::_));
   EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_));
 
@@ -822,7 +834,7 @@
   // The second call should start scrolling in the -X direction.
   EXPECT_SET_NEEDS_ANIMATE_INPUT(1);
   EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_))
-      .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED));
+      .WillOnce(testing::Return(kImplThreadScrollState));
   EXPECT_CALL(
       mock_input_handler_,
       ScrollBy(testing::Property(&cc::ScrollState::delta_x, testing::Lt(0))))
@@ -839,7 +851,7 @@
   // rest of the fling can be
   // transferred to the main thread.
   EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_))
-      .WillOnce(testing::Return(cc::InputHandler::SCROLL_ON_MAIN_THREAD));
+      .WillOnce(testing::Return(kMainThreadScrollState));
   EXPECT_CALL(mock_input_handler_, ScrollBy(testing::_)).Times(0);
   EXPECT_CALL(mock_input_handler_, ScrollEnd(testing::_)).Times(0);
   // Expected wheel fling animation parameters:
@@ -907,7 +919,7 @@
                          modifiers);
   EXPECT_SET_NEEDS_ANIMATE_INPUT(1);
   EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_))
-      .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED));
+      .WillOnce(testing::Return(kImplThreadScrollState));
   EXPECT_CALL(mock_input_handler_, ScrollEnd(testing::_));
   EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_));
 
@@ -926,7 +938,7 @@
   // The second call should start scrolling in the -X direction.
   EXPECT_SET_NEEDS_ANIMATE_INPUT(1);
   EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_))
-      .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED));
+      .WillOnce(testing::Return(kImplThreadScrollState));
   EXPECT_CALL(
       mock_input_handler_,
       ScrollBy(testing::Property(&cc::ScrollState::delta_x, testing::Lt(0))))
@@ -943,7 +955,8 @@
   // rest of the fling can be
   // transferred to the main thread.
   EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_))
-      .WillOnce(testing::Return(cc::InputHandler::SCROLL_ON_MAIN_THREAD));
+      .WillOnce(testing::Return(kMainThreadScrollState));
+
   EXPECT_CALL(mock_input_handler_, ScrollBy(testing::_)).Times(0);
   EXPECT_CALL(mock_input_handler_, ScrollEnd(testing::_)).Times(0);
 
@@ -1007,7 +1020,7 @@
                          modifiers);
   EXPECT_SET_NEEDS_ANIMATE_INPUT(1);
   EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_))
-      .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED));
+      .WillOnce(testing::Return(kImplThreadScrollState));
   EXPECT_CALL(mock_input_handler_, ScrollEnd(testing::_));
   expected_disposition_ = InputHandlerProxy::DID_HANDLE;
   EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_));
@@ -1026,7 +1039,7 @@
   // Tick the second fling once normally.
   EXPECT_SET_NEEDS_ANIMATE_INPUT(1);
   EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_))
-      .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED));
+      .WillOnce(testing::Return(kImplThreadScrollState));
   EXPECT_CALL(
       mock_input_handler_,
       ScrollBy(testing::Property(&cc::ScrollState::delta_y, testing::Gt(0))))
@@ -1039,7 +1052,7 @@
 
   // Then abort the second fling.
   EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_))
-      .WillOnce(testing::Return(cc::InputHandler::SCROLL_ON_MAIN_THREAD));
+      .WillOnce(testing::Return(kMainThreadScrollState));
   EXPECT_CALL(mock_input_handler_, ScrollBy(testing::_)).Times(0);
   EXPECT_CALL(mock_input_handler_, ScrollEnd(testing::_)).Times(0);
 
@@ -1072,7 +1085,7 @@
   VERIFY_AND_RESET_MOCKS();
 
   EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_))
-      .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED));
+      .WillOnce(testing::Return(kImplThreadScrollState));
   gesture_.type = WebInputEvent::GestureScrollBegin;
   gesture_.sourceDevice = blink::WebGestureDeviceTouchscreen;
   EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_));
@@ -1080,7 +1093,7 @@
   VERIFY_AND_RESET_MOCKS();
 
   EXPECT_CALL(mock_input_handler_, FlingScrollBegin())
-      .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED));
+      .WillOnce(testing::Return(kImplThreadScrollState));
   EXPECT_SET_NEEDS_ANIMATE_INPUT(1);
 
   gesture_.type = WebInputEvent::GestureFlingStart;
@@ -1106,7 +1119,7 @@
   VERIFY_AND_RESET_MOCKS();
 
   EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_))
-      .WillOnce(testing::Return(cc::InputHandler::SCROLL_ON_MAIN_THREAD));
+      .WillOnce(testing::Return(kMainThreadScrollState));
 
   gesture_.type = WebInputEvent::GestureScrollBegin;
   EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_));
@@ -1133,7 +1146,7 @@
   VERIFY_AND_RESET_MOCKS();
 
   EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_))
-      .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED));
+      .WillOnce(testing::Return(kImplThreadScrollState));
 
   gesture_.type = WebInputEvent::GestureScrollBegin;
   gesture_.sourceDevice = blink::WebGestureDeviceTouchscreen;
@@ -1145,7 +1158,7 @@
   // Flings ignored by the InputHandler should be dropped, signalling the end
   // of the touch scroll sequence.
   EXPECT_CALL(mock_input_handler_, FlingScrollBegin())
-      .WillOnce(testing::Return(cc::InputHandler::SCROLL_IGNORED));
+      .WillOnce(testing::Return(kScrollIgnoredScrollState));
 
   gesture_.type = WebInputEvent::GestureFlingStart;
   gesture_.sourceDevice = blink::WebGestureDeviceTouchscreen;
@@ -1157,7 +1170,7 @@
   // GestureFlingCancel, as the original GestureFlingStart was dropped.
   expected_disposition_ = InputHandlerProxy::DID_HANDLE;
   EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_))
-      .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED));
+      .WillOnce(testing::Return(kImplThreadScrollState));
   gesture_.type = WebInputEvent::GestureScrollBegin;
   gesture_.sourceDevice = blink::WebGestureDeviceTouchscreen;
   EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_));
@@ -1171,7 +1184,7 @@
   VERIFY_AND_RESET_MOCKS();
 
   EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_))
-      .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED));
+      .WillOnce(testing::Return(kImplThreadScrollState));
 
   gesture_.type = WebInputEvent::GestureScrollBegin;
   gesture_.sourceDevice = blink::WebGestureDeviceTouchscreen;
@@ -1193,7 +1206,7 @@
                          modifiers);
   EXPECT_SET_NEEDS_ANIMATE_INPUT(1);
   EXPECT_CALL(mock_input_handler_, FlingScrollBegin())
-      .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED));
+      .WillOnce(testing::Return(kImplThreadScrollState));
   EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_));
 
   VERIFY_AND_RESET_MOCKS();
@@ -1232,7 +1245,7 @@
   VERIFY_AND_RESET_MOCKS();
 
   EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_))
-      .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED));
+      .WillOnce(testing::Return(kImplThreadScrollState));
 
   gesture_.type = WebInputEvent::GestureScrollBegin;
   gesture_.sourceDevice = blink::WebGestureDeviceTouchscreen;
@@ -1256,7 +1269,7 @@
                          modifiers);
   EXPECT_SET_NEEDS_ANIMATE_INPUT(1);
   EXPECT_CALL(mock_input_handler_, FlingScrollBegin())
-      .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED));
+      .WillOnce(testing::Return(kImplThreadScrollState));
   EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_));
 
   VERIFY_AND_RESET_MOCKS();
@@ -1288,7 +1301,7 @@
   VERIFY_AND_RESET_MOCKS();
 
   EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_))
-      .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED));
+      .WillOnce(testing::Return(kImplThreadScrollState));
 
   gesture_.type = WebInputEvent::GestureScrollBegin;
   gesture_.sourceDevice = blink::WebGestureDeviceTouchscreen;
@@ -1315,7 +1328,7 @@
   gesture_.modifiers = modifiers;
   EXPECT_SET_NEEDS_ANIMATE_INPUT(1);
   EXPECT_CALL(mock_input_handler_, FlingScrollBegin())
-      .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED));
+      .WillOnce(testing::Return(kImplThreadScrollState));
   EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_));
 
   VERIFY_AND_RESET_MOCKS();
@@ -1353,7 +1366,7 @@
   VERIFY_AND_RESET_MOCKS();
 
   EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_))
-      .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED));
+      .WillOnce(testing::Return(kImplThreadScrollState));
 
   gesture_.type = WebInputEvent::GestureScrollBegin;
   EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_));
@@ -1378,7 +1391,7 @@
                          modifiers);
   EXPECT_SET_NEEDS_ANIMATE_INPUT(1);
   EXPECT_CALL(mock_input_handler_, FlingScrollBegin())
-      .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED));
+      .WillOnce(testing::Return(kImplThreadScrollState));
   EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_));
 
   // |gesture_scroll_on_impl_thread_| should still be true after
@@ -1426,7 +1439,7 @@
   VERIFY_AND_RESET_MOCKS();
 
   EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_))
-      .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED));
+      .WillOnce(testing::Return(kImplThreadScrollState));
 
   gesture_.type = WebInputEvent::GestureScrollBegin;
   EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_));
@@ -1448,7 +1461,7 @@
                          fling_point, fling_global_point, modifiers);
   EXPECT_SET_NEEDS_ANIMATE_INPUT(1);
   EXPECT_CALL(mock_input_handler_, FlingScrollBegin())
-      .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED));
+      .WillOnce(testing::Return(kImplThreadScrollState));
   EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_));
 
   // |gesture_scroll_on_impl_thread_| should still be true after
@@ -1461,7 +1474,7 @@
   // result, this scroll begin will cancel the previous fling.
   EXPECT_CALL(mock_input_handler_, ScrollEnd(testing::_));
   EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_))
-      .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED));
+      .WillOnce(testing::Return(kImplThreadScrollState));
 
   gesture_.type = WebInputEvent::GestureScrollBegin;
   EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_));
@@ -1484,7 +1497,7 @@
   gesture_.data.flingStart.velocityX = fling_delta.x;
   gesture_.data.flingStart.velocityY = fling_delta.y;
   EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_))
-      .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED));
+      .WillOnce(testing::Return(kImplThreadScrollState));
   EXPECT_CALL(mock_input_handler_, ScrollEnd(testing::_));
   EXPECT_SET_NEEDS_ANIMATE_INPUT(1);
   EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_));
@@ -1498,7 +1511,7 @@
 
   // The second animate starts scrolling in the positive X and Y directions.
   EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_))
-      .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED));
+      .WillOnce(testing::Return(kImplThreadScrollState));
   EXPECT_CALL(
       mock_input_handler_,
       ScrollBy(testing::Property(&cc::ScrollState::delta_y, testing::Lt(0))))
@@ -1517,7 +1530,7 @@
   overscroll.accumulated_root_overscroll = gfx::Vector2dF(0, 100);
   overscroll.unused_scroll_delta = gfx::Vector2dF(0, 10);
   EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_))
-      .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED));
+      .WillOnce(testing::Return(kImplThreadScrollState));
   EXPECT_CALL(
       mock_input_handler_,
       ScrollBy(testing::Property(&cc::ScrollState::delta_y, testing::Lt(0))))
@@ -1538,7 +1551,7 @@
   // The next call to animate will no longer scroll vertically.
   EXPECT_SET_NEEDS_ANIMATE_INPUT(1);
   EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_))
-      .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED));
+      .WillOnce(testing::Return(kImplThreadScrollState));
   EXPECT_CALL(
       mock_input_handler_,
       ScrollBy(testing::Property(&cc::ScrollState::delta_y, testing::Eq(0))))
@@ -1555,7 +1568,7 @@
   VERIFY_AND_RESET_MOCKS();
 
   EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_))
-      .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED));
+      .WillOnce(testing::Return(kImplThreadScrollState));
 
   gesture_.type = WebInputEvent::GestureScrollBegin;
   gesture_.sourceDevice = blink::WebGestureDeviceTouchscreen;
@@ -1579,7 +1592,7 @@
                          modifiers);
   EXPECT_SET_NEEDS_ANIMATE_INPUT(1);
   EXPECT_CALL(mock_input_handler_, FlingScrollBegin())
-      .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED));
+      .WillOnce(testing::Return(kImplThreadScrollState));
   EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_));
 
   VERIFY_AND_RESET_MOCKS();
@@ -1636,7 +1649,7 @@
   VERIFY_AND_RESET_MOCKS();
 
   EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_))
-      .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED));
+      .WillOnce(testing::Return(kImplThreadScrollState));
   gesture_.type = WebInputEvent::GestureScrollBegin;
   gesture_.sourceDevice = blink::WebGestureDeviceTouchscreen;
   EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_));
@@ -1649,7 +1662,7 @@
   gesture_.data.flingStart.velocityX = fling_delta.x;
   gesture_.data.flingStart.velocityY = fling_delta.y;
   EXPECT_CALL(mock_input_handler_, FlingScrollBegin())
-      .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED));
+      .WillOnce(testing::Return(kImplThreadScrollState));
   EXPECT_SET_NEEDS_ANIMATE_INPUT(1);
   EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_));
   VERIFY_AND_RESET_MOCKS();
@@ -1790,7 +1803,7 @@
   VERIFY_AND_RESET_MOCKS();
 
   EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_))
-      .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED));
+      .WillOnce(testing::Return(kImplThreadScrollState));
   gesture_.type = WebInputEvent::GestureScrollBegin;
   gesture_.sourceDevice = blink::WebGestureDeviceTouchscreen;
   EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_));
@@ -1811,7 +1824,7 @@
   gesture_.data.flingStart.velocityX = fling_delta.x;
   gesture_.data.flingStart.velocityY = fling_delta.y;
   EXPECT_CALL(mock_input_handler_, FlingScrollBegin())
-      .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED));
+      .WillOnce(testing::Return(kImplThreadScrollState));
   EXPECT_SET_NEEDS_ANIMATE_INPUT(1);
   EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_));
   EXPECT_TRUE(input_handler_->gesture_scroll_on_impl_thread_for_testing());
@@ -1842,7 +1855,7 @@
   VERIFY_AND_RESET_MOCKS();
 
   EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_))
-      .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED));
+      .WillOnce(testing::Return(kImplThreadScrollState));
 
   gesture_.type = WebInputEvent::GestureScrollBegin;
   gesture_.sourceDevice = blink::WebGestureDeviceTouchscreen;
@@ -1866,7 +1879,7 @@
                          modifiers);
   EXPECT_SET_NEEDS_ANIMATE_INPUT(1);
   EXPECT_CALL(mock_input_handler_, FlingScrollBegin())
-      .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED));
+      .WillOnce(testing::Return(kImplThreadScrollState));
   EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_));
 
   VERIFY_AND_RESET_MOCKS();
@@ -2051,7 +2064,7 @@
       .WillOnce(testing::Return(false));
   EXPECT_CALL(mock_input_handler_, ScrollEnd(testing::_));
   EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_))
-      .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED));
+      .WillOnce(testing::Return(kImplThreadScrollState));
 
   time += dt;
   gesture_.timeStampSeconds = InSecondsF(time);
@@ -2092,7 +2105,7 @@
   time += base::TimeDelta::FromMilliseconds(100);
   EXPECT_CALL(mock_input_handler_, ScrollEnd(testing::_));
   EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_))
-      .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED));
+      .WillOnce(testing::Return(kImplThreadScrollState));
   Animate(time);
 
   VERIFY_AND_RESET_MOCKS();
@@ -2137,7 +2150,7 @@
   gesture_.data.scrollUpdate.deltaY = -40;
   EXPECT_CALL(mock_input_handler_, ScrollEnd(testing::_));
   EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_))
-      .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED));
+      .WillOnce(testing::Return(kImplThreadScrollState));
   EXPECT_CALL(mock_input_handler_, ScrollBy(testing::_))
       .WillOnce(testing::Return(scroll_result_did_scroll_));
   EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_));
@@ -2220,7 +2233,7 @@
   gesture_.data.scrollUpdate.deltaX = -fling_delta.x;
   EXPECT_CALL(mock_input_handler_, ScrollEnd(testing::_));
   EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_))
-      .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED));
+      .WillOnce(testing::Return(kImplThreadScrollState));
   EXPECT_CALL(mock_input_handler_,
               ScrollBy(testing::Property(&cc::ScrollState::delta_x,
                                          testing::Eq(fling_delta.x))))
@@ -2327,7 +2340,7 @@
       .WillOnce(testing::Return(scroll_result_did_not_scroll_));
   EXPECT_CALL(mock_input_handler_, ScrollEnd(testing::_));
   EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_))
-      .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED));
+      .WillOnce(testing::Return(kImplThreadScrollState));
   Animate(time);
 
   VERIFY_AND_RESET_MOCKS();
@@ -2377,7 +2390,7 @@
   gesture_.data.flingStart.velocityY = fling_delta.y;
   EXPECT_SET_NEEDS_ANIMATE_INPUT(1);
   EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_))
-      .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED));
+      .WillOnce(testing::Return(kImplThreadScrollState));
   EXPECT_CALL(mock_input_handler_, ScrollEnd(testing::_));
   EXPECT_EQ(InputHandlerProxy::DID_HANDLE,
       input_handler_->HandleInputEvent(gesture_));
diff --git a/ui/ozone/ozone.gni b/ui/ozone/ozone.gni
index c5855dfe..7f75f2d 100644
--- a/ui/ozone/ozone.gni
+++ b/ui/ozone/ozone.gni
@@ -3,10 +3,11 @@
 # found in the LICENSE file.
 
 import("//build/config/chromecast_build.gni")
+import("//build/config/ui.gni")
 
 declare_args() {
   # Select platforms automatically. Turn this off for manual control.
-  ozone_auto_platforms = true
+  ozone_auto_platforms = use_ozone
 
   # This enables memory-mapped access to accelerated graphics buffers via the
   # VGEM ("virtual GEM") driver. This is currently only available on Chrome OS
@@ -61,3 +62,8 @@
     }
   }
 }
+
+assert(use_ozone || !(ozone_platform_caca || ozone_platform_cast ||
+                          ozone_platform_egltest || ozone_platform_gbm ||
+                          ozone_platform_ozonex || ozone_platform_headless),
+       "Must set use_ozone to select ozone platforms")
diff --git a/ui/shell_dialogs/BUILD.gn b/ui/shell_dialogs/BUILD.gn
index 4ecd64c..01afac9a 100644
--- a/ui/shell_dialogs/BUILD.gn
+++ b/ui/shell_dialogs/BUILD.gn
@@ -70,10 +70,6 @@
       "select_file_dialog_auraandroid.h",
     ]
   }
-
-  if (is_win) {
-    deps += [ "//win8:metro_viewer" ]
-  }
 }
 
 test("shell_dialogs_unittests") {
diff --git a/ui/shell_dialogs/select_file_dialog_win.cc b/ui/shell_dialogs/select_file_dialog_win.cc
index 40215a34..4cd8896b 100644
--- a/ui/shell_dialogs/select_file_dialog_win.cc
+++ b/ui/shell_dialogs/select_file_dialog_win.cc
@@ -30,7 +30,6 @@
 #include "ui/shell_dialogs/base_shell_dialog_win.h"
 #include "ui/shell_dialogs/shell_dialogs_delegate.h"
 #include "ui/strings/grit/ui_strings.h"
-#include "win8/viewer/metro_viewer_process_host.h"
 
 namespace {
 
@@ -328,59 +327,6 @@
     void* params) {
   has_multiple_file_type_choices_ =
       file_types ? file_types->extensions.size() > 1 : true;
-  // If the owning_window passed in is in metro then we need to forward the
-  // file open/save operations to metro.
-  if (GetShellDialogsDelegate() &&
-      GetShellDialogsDelegate()->IsWindowInMetro(owning_window)) {
-    if (type == SELECT_SAVEAS_FILE) {
-      win8::MetroViewerProcessHost::HandleSaveFile(
-          title,
-          default_path,
-          GetFilterForFileTypes(file_types),
-          file_type_index,
-          default_extension,
-          base::Bind(&ui::SelectFileDialog::Listener::FileSelected,
-                     base::Unretained(listener_)),
-          base::Bind(&ui::SelectFileDialog::Listener::FileSelectionCanceled,
-                     base::Unretained(listener_)));
-      return;
-    } else if (type == SELECT_OPEN_FILE) {
-      win8::MetroViewerProcessHost::HandleOpenFile(
-          title,
-          default_path,
-          GetFilterForFileTypes(file_types),
-          base::Bind(&ui::SelectFileDialog::Listener::FileSelected,
-                     base::Unretained(listener_)),
-          base::Bind(&ui::SelectFileDialog::Listener::FileSelectionCanceled,
-                     base::Unretained(listener_)));
-      return;
-    } else if (type == SELECT_OPEN_MULTI_FILE) {
-      win8::MetroViewerProcessHost::HandleOpenMultipleFiles(
-          title,
-          default_path,
-          GetFilterForFileTypes(file_types),
-          base::Bind(&ui::SelectFileDialog::Listener::MultiFilesSelected,
-                     base::Unretained(listener_)),
-          base::Bind(&ui::SelectFileDialog::Listener::FileSelectionCanceled,
-                     base::Unretained(listener_)));
-      return;
-    } else if (type == SELECT_FOLDER || type == SELECT_UPLOAD_FOLDER) {
-      base::string16 title_string = title;
-      if (type == SELECT_UPLOAD_FOLDER && title_string.empty()) {
-        // If it's for uploading don't use default dialog title to
-        // make sure we clearly tell it's for uploading.
-        title_string = l10n_util::GetStringUTF16(
-            IDS_SELECT_UPLOAD_FOLDER_DIALOG_TITLE);
-      }
-      win8::MetroViewerProcessHost::HandleSelectFolder(
-          title_string,
-          base::Bind(&ui::SelectFileDialog::Listener::FileSelected,
-                     base::Unretained(listener_)),
-          base::Bind(&ui::SelectFileDialog::Listener::FileSelectionCanceled,
-                     base::Unretained(listener_)));
-      return;
-    }
-  }
   HWND owner = owning_window && owning_window->GetRootWindow()
       ? owning_window->GetHost()->GetAcceleratedWidget() : NULL;
 
diff --git a/ui/shell_dialogs/shell_dialogs.gyp b/ui/shell_dialogs/shell_dialogs.gyp
index 0d541fc..2329f8f 100644
--- a/ui/shell_dialogs/shell_dialogs.gyp
+++ b/ui/shell_dialogs/shell_dialogs.gyp
@@ -74,13 +74,6 @@
             },
           }
         ],
-        ['OS=="win"',
-          {
-            'dependencies': [
-              '../../win8/win8.gyp:metro_viewer',
-            ],
-          }
-        ],
       ],
     },  # target_name: shell_dialogs
     {
diff --git a/win8/BUILD.gn b/win8/BUILD.gn
index fb43d2d..7b36f33 100644
--- a/win8/BUILD.gn
+++ b/win8/BUILD.gn
@@ -2,31 +2,6 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-source_set("metro_viewer_constants") {
-  sources = [
-    "viewer/metro_viewer_constants.cc",
-    "viewer/metro_viewer_constants.h",
-  ]
-}
-
-component("metro_viewer") {
-  sources = [
-    "viewer/metro_viewer_process_host.cc",
-    "viewer/metro_viewer_process_host.h",
-  ]
-
-  defines = [ "METRO_VIEWER_IMPLEMENTATION" ]
-
-  deps = [
-    ":metro_viewer_constants",
-    "//base",
-    "//ipc",
-    "//ui/aura",
-    "//ui/gfx",
-    "//ui/metro_viewer",
-  ]
-}
-
 source_set("test_support_win8") {
   sources = [
     "test/open_with_dialog_async.cc",
diff --git a/win8/delegate_execute/BUILD.gn b/win8/delegate_execute/BUILD.gn
index 8309dc66..4b7d911 100644
--- a/win8/delegate_execute/BUILD.gn
+++ b/win8/delegate_execute/BUILD.gn
@@ -50,10 +50,6 @@
     "//ui/gfx/geometry",
   ]
 
-  if (use_aura) {
-    public_deps += [ "//win8:metro_viewer_constants" ]
-  }
-
   if (is_chrome_branded) {
     public_deps += [ "//google_update" ]
   }
diff --git a/win8/delegate_execute/command_execute_impl.cc b/win8/delegate_execute/command_execute_impl.cc
index 236f862..bae9ee8 100644
--- a/win8/delegate_execute/command_execute_impl.cc
+++ b/win8/delegate_execute/command_execute_impl.cc
@@ -32,7 +32,6 @@
 #include "ui/gfx/win/dpi.h"
 #include "win8/delegate_execute/chrome_util.h"
 #include "win8/delegate_execute/delegate_execute_util.h"
-#include "win8/viewer/metro_viewer_constants.h"
 
 namespace {
 // Helper function to retrieve the url from IShellItem interface passed in.
@@ -67,44 +66,6 @@
   return S_OK;
 }
 
-bool LaunchChromeBrowserProcess() {
-  base::FilePath delegate_exe_path;
-  if (!PathService::Get(base::FILE_EXE, &delegate_exe_path))
-    return false;
-
-  // First try and go up a level to find chrome.exe.
-  base::FilePath chrome_exe_path =
-      delegate_exe_path.DirName()
-                       .DirName()
-                       .Append(chrome::kBrowserProcessExecutableName);
-  if (!base::PathExists(chrome_exe_path)) {
-    // Try looking in the current directory if we couldn't find it one up in
-    // order to support developer installs.
-    chrome_exe_path =
-        delegate_exe_path.DirName()
-                         .Append(chrome::kBrowserProcessExecutableName);
-  }
-
-  if (!base::PathExists(chrome_exe_path)) {
-    AtlTrace("Could not locate chrome.exe at: %ls\n",
-             chrome_exe_path.value().c_str());
-    return false;
-  }
-
-  base::CommandLine cl(chrome_exe_path);
-
-  // Prevent a Chrome window from showing up on the desktop.
-  cl.AppendSwitch(switches::kSilentLaunch);
-
-  // Tell Chrome to connect to the Metro viewer process.
-  cl.AppendSwitch(switches::kViewerConnect);
-
-  base::LaunchOptions launch_options;
-  launch_options.start_hidden = true;
-
-  return base::LaunchProcess(cl, launch_options).IsValid();
-}
-
 }  // namespace
 
 bool CommandExecuteImpl::path_provider_initialized_ = false;
@@ -219,18 +180,8 @@
     return E_FAIL;
   }
 
-  EC_HOST_UI_MODE mode = GetLaunchMode();
-  *pahe = (mode == ECHUIM_DESKTOP) ? AHE_DESKTOP : AHE_IMMERSIVE;
-
-  // If we're going to return AHE_IMMERSIVE, then both the browser process and
-  // the metro viewer need to launch and connect before the user can start
-  // browsing.  However we must not launch the metro viewer until we get a
-  // call to CommandExecuteImpl::Execute().  If we wait until then to launch
-  // the browser process as well, it will appear laggy while they connect to
-  // each other, so we pre-launch the browser process now.
-  if (*pahe == AHE_IMMERSIVE && verb_ != win8::kMetroViewerConnectVerb) {
-    LaunchChromeBrowserProcess();
-  }
+  // TODO(scottmg): Can all go eventually https://crbug.com/558054.
+  *pahe = AHE_DESKTOP;
   return S_OK;
 }
 
diff --git a/win8/delegate_execute/delegate_execute.gyp b/win8/delegate_execute/delegate_execute.gyp
index 8dcd71f..b863dc56 100644
--- a/win8/delegate_execute/delegate_execute.gyp
+++ b/win8/delegate_execute/delegate_execute.gyp
@@ -73,11 +73,6 @@
         },
       },
       'conditions': [
-        ['use_aura==1', {
-          'dependencies': [
-            '../win8.gyp:metro_viewer_constants',
-          ],
-        }],
         ['branding!="Chrome"', {
           'dependencies!': [
             '../../google_update/google_update.gyp:google_update',
diff --git a/win8/metro_driver/BUILD.gn b/win8/metro_driver/BUILD.gn
index 68c9a90f..fc666901 100644
--- a/win8/metro_driver/BUILD.gn
+++ b/win8/metro_driver/BUILD.gn
@@ -10,9 +10,6 @@
   sources = [
     "display_properties.cc",
     "display_properties.h",
-    "metro_driver.cc",
-    "metro_driver.h",
-    "metro_driver_win7.cc",
     "stdafx.h",
     "winrt_utils.cc",
     "winrt_utils.h",
@@ -36,17 +33,12 @@
 
   if (use_aura) {
     sources += [
-      "chrome_app_view_ash.cc",
-      "chrome_app_view_ash.h",
       "direct3d_helper.cc",
       "direct3d_helper.h",
-      "file_picker_ash.cc",
-      "file_picker_ash.h",
     ]
 
     deps += [
       "//ui/events:gesture_detection",
-      "//win8:metro_viewer_constants",
       "//win8/metro_driver/ime",
     ]
   } else {
@@ -57,8 +49,6 @@
       "chrome_url_launch_handler.h",
       "devices_handler.cc",
       "devices_handler.h",
-      "file_picker.cc",
-      "file_picker.h",
       "metro_dialog_box.cc",
       "metro_dialog_box.h",
       "print_document_source.cc",
diff --git a/win8/metro_driver/chrome_app_view_ash.cc b/win8/metro_driver/chrome_app_view_ash.cc
deleted file mode 100644
index 01f9ba23..0000000
--- a/win8/metro_driver/chrome_app_view_ash.cc
+++ /dev/null
@@ -1,1464 +0,0 @@
-// Copyright (c) 2012 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 "win8/metro_driver/stdafx.h"
-#include "win8/metro_driver/chrome_app_view_ash.h"
-
-#include <corewindow.h>
-#include <shellapi.h>
-#include <stdint.h>
-#include <windows.foundation.h>
-
-#include "base/bind.h"
-#include "base/command_line.h"
-#include "base/files/file_path.h"
-#include "base/macros.h"
-#include "base/message_loop/message_loop.h"
-#include "base/path_service.h"
-#include "base/single_thread_task_runner.h"
-#include "base/win/windows_version.h"
-#include "chrome/common/chrome_switches.h"
-#include "ipc/ipc_channel.h"
-#include "ipc/ipc_channel_proxy.h"
-#include "ipc/ipc_sender.h"
-#include "ui/events/gesture_detection/motion_event.h"
-#include "ui/events/win/system_event_state_lookup.h"
-#include "ui/gfx/geometry/point_conversions.h"
-#include "ui/gfx/win/dpi.h"
-#include "ui/metro_viewer/metro_viewer_messages.h"
-#include "win8/metro_driver/file_picker_ash.h"
-#include "win8/metro_driver/ime/ime_popup_monitor.h"
-#include "win8/metro_driver/ime/input_source.h"
-#include "win8/metro_driver/ime/text_service.h"
-#include "win8/metro_driver/metro_driver.h"
-#include "win8/metro_driver/winrt_utils.h"
-#include "win8/viewer/metro_viewer_constants.h"
-
-typedef winfoundtn::ITypedEventHandler<
-    winapp::Core::CoreApplicationView*,
-    winapp::Activation::IActivatedEventArgs*> ActivatedHandler;
-
-typedef winfoundtn::ITypedEventHandler<
-    winui::Core::CoreWindow*,
-    winui::Core::PointerEventArgs*> PointerEventHandler;
-
-typedef winfoundtn::ITypedEventHandler<
-    winui::Core::CoreWindow*,
-    winui::Core::KeyEventArgs*> KeyEventHandler;
-
-typedef winfoundtn::ITypedEventHandler<
-    winui::Core::CoreDispatcher*,
-    winui::Core::AcceleratorKeyEventArgs*> AcceleratorKeyEventHandler;
-
-typedef winfoundtn::ITypedEventHandler<
-    winui::Core::CoreWindow*,
-    winui::Core::CharacterReceivedEventArgs*> CharEventHandler;
-
-typedef winfoundtn::ITypedEventHandler<
-    winui::Core::CoreWindow*,
-    winui::Core::WindowActivatedEventArgs*> WindowActivatedHandler;
-
-typedef winfoundtn::ITypedEventHandler<
-    winui::Core::CoreWindow*,
-    winui::Core::WindowSizeChangedEventArgs*> SizeChangedHandler;
-
-typedef winfoundtn::ITypedEventHandler<
-    winui::Input::EdgeGesture*,
-    winui::Input::EdgeGestureEventArgs*> EdgeEventHandler;
-
-// This function is exported by chrome.exe.
-typedef int (__cdecl *BreakpadExceptionHandler)(EXCEPTION_POINTERS* info);
-
-// Global information used across the metro driver.
-struct Globals {
-  winapp::Activation::ApplicationExecutionState previous_state;
-  winapp::Core::ICoreApplicationExit* app_exit;
-  BreakpadExceptionHandler breakpad_exception_handler;
-} globals;
-
-extern float GetModernUIScale();
-
-namespace {
-
-enum KeyModifier {
-  NONE,
-  SHIFT = 1,
-  CONTROL = 2,
-  ALT = 4
-};
-
-const int kChromeChannelPollTimerMs = 100;
-
-// Helper function to send keystrokes via the SendInput function.
-// mnemonic_char: The keystroke to be sent.
-// modifiers: Combination with Alt, Ctrl, Shift, etc.
-void SendKeySequence(
-    WORD mnemonic_char, KeyModifier modifiers) {
-  INPUT keys[4] = {};  // Keyboard events
-  int key_count = 0;  // Number of generated events
-
-  if (modifiers & SHIFT) {
-    keys[key_count].type = INPUT_KEYBOARD;
-    keys[key_count].ki.wVk = VK_SHIFT;
-    keys[key_count].ki.wScan = MapVirtualKey(VK_SHIFT, 0);
-    key_count++;
-  }
-
-  if (modifiers & CONTROL) {
-    keys[key_count].type = INPUT_KEYBOARD;
-    keys[key_count].ki.wVk = VK_CONTROL;
-    keys[key_count].ki.wScan = MapVirtualKey(VK_CONTROL, 0);
-    key_count++;
-  }
-
-  if (modifiers & ALT) {
-    keys[key_count].type = INPUT_KEYBOARD;
-    keys[key_count].ki.wVk = VK_MENU;
-    keys[key_count].ki.wScan = MapVirtualKey(VK_MENU, 0);
-    key_count++;
-  }
-
-  keys[key_count].type = INPUT_KEYBOARD;
-  keys[key_count].ki.wVk = mnemonic_char;
-  keys[key_count].ki.wScan = MapVirtualKey(mnemonic_char, 0);
-  key_count++;
-
-  bool should_sleep = key_count > 1;
-
-  // Send key downs.
-  for (int i = 0; i < key_count; i++) {
-    SendInput(1, &keys[ i ], sizeof(keys[0]));
-    keys[i].ki.dwFlags |= KEYEVENTF_KEYUP;
-    if (should_sleep)
-      Sleep(10);
-  }
-
-  // Now send key ups in reverse order.
-  for (int i = key_count; i; i--) {
-    SendInput(1, &keys[ i - 1 ], sizeof(keys[0]));
-    if (should_sleep)
-      Sleep(10);
-  }
-}
-
-class ChromeChannelListener : public IPC::Listener {
- public:
-  ChromeChannelListener(base::MessageLoop* ui_loop, ChromeAppViewAsh* app_view)
-      : ui_task_runner_(ui_loop->task_runner()), app_view_(app_view) {}
-
-  bool OnMessageReceived(const IPC::Message& message) override {
-    IPC_BEGIN_MESSAGE_MAP(ChromeChannelListener, message)
-      IPC_MESSAGE_HANDLER(MetroViewerHostMsg_ActivateDesktop,
-                          OnActivateDesktop)
-      IPC_MESSAGE_HANDLER(MetroViewerHostMsg_MetroExit, OnMetroExit)
-      IPC_MESSAGE_HANDLER(MetroViewerHostMsg_OpenURLOnDesktop,
-                          OnOpenURLOnDesktop)
-      IPC_MESSAGE_HANDLER(MetroViewerHostMsg_SetCursor, OnSetCursor)
-      IPC_MESSAGE_HANDLER(MetroViewerHostMsg_DisplayFileOpen,
-                          OnDisplayFileOpenDialog)
-      IPC_MESSAGE_HANDLER(MetroViewerHostMsg_DisplayFileSaveAs,
-                          OnDisplayFileSaveAsDialog)
-      IPC_MESSAGE_HANDLER(MetroViewerHostMsg_DisplaySelectFolder,
-                          OnDisplayFolderPicker)
-      IPC_MESSAGE_HANDLER(MetroViewerHostMsg_SetCursorPos, OnSetCursorPos)
-      IPC_MESSAGE_HANDLER(MetroViewerHostMsg_ImeCancelComposition,
-                          OnImeCancelComposition)
-      IPC_MESSAGE_HANDLER(MetroViewerHostMsg_ImeTextInputClientUpdated,
-                          OnImeTextInputClientChanged)
-      IPC_MESSAGE_UNHANDLED(__debugbreak())
-    IPC_END_MESSAGE_MAP()
-    return true;
-  }
-
-  void OnChannelError() override {
-    DVLOG(1) << "Channel error. Exiting.";
-    ui_task_runner_->PostTask(
-        FROM_HERE,
-        base::Bind(&ChromeAppViewAsh::OnMetroExit, base::Unretained(app_view_),
-                   TERMINATE_USING_KEY_SEQUENCE));
-
-    // In early Windows 8 versions the code above sometimes fails so we call
-    // it a second time with a NULL window which just calls Exit().
-    ui_task_runner_->PostDelayedTask(
-        FROM_HERE,
-        base::Bind(&ChromeAppViewAsh::OnMetroExit, base::Unretained(app_view_),
-                   TERMINATE_USING_PROCESS_EXIT),
-        base::TimeDelta::FromMilliseconds(100));
-  }
-
- private:
-  void OnActivateDesktop(const base::FilePath& shortcut, bool ash_exit) {
-    ui_task_runner_->PostTask(
-        FROM_HERE, base::Bind(&ChromeAppViewAsh::OnActivateDesktop,
-                              base::Unretained(app_view_), shortcut, ash_exit));
-  }
-
-  void OnMetroExit() {
-    ui_task_runner_->PostTask(
-        FROM_HERE,
-        base::Bind(&ChromeAppViewAsh::OnMetroExit, base::Unretained(app_view_),
-                   TERMINATE_USING_KEY_SEQUENCE));
-  }
-
-  void OnOpenURLOnDesktop(const base::FilePath& shortcut,
-                          const base::string16& url) {
-    ui_task_runner_->PostTask(
-        FROM_HERE, base::Bind(&ChromeAppViewAsh::OnOpenURLOnDesktop,
-                              base::Unretained(app_view_), shortcut, url));
-  }
-
-  void OnSetCursor(int64_t cursor) {
-    ui_task_runner_->PostTask(
-        FROM_HERE,
-        base::Bind(&ChromeAppViewAsh::OnSetCursor, base::Unretained(app_view_),
-                   reinterpret_cast<HCURSOR>(cursor)));
-  }
-
-  void OnDisplayFileOpenDialog(const base::string16& title,
-                               const base::string16& filter,
-                               const base::FilePath& default_path,
-                               bool allow_multiple_files) {
-    ui_task_runner_->PostTask(
-        FROM_HERE, base::Bind(&ChromeAppViewAsh::OnDisplayFileOpenDialog,
-                              base::Unretained(app_view_), title, filter,
-                              default_path, allow_multiple_files));
-  }
-
-  void OnDisplayFileSaveAsDialog(
-    const MetroViewerHostMsg_SaveAsDialogParams& params) {
-    ui_task_runner_->PostTask(
-        FROM_HERE, base::Bind(&ChromeAppViewAsh::OnDisplayFileSaveAsDialog,
-                              base::Unretained(app_view_), params));
-  }
-
-  void OnDisplayFolderPicker(const base::string16& title) {
-    ui_task_runner_->PostTask(
-        FROM_HERE, base::Bind(&ChromeAppViewAsh::OnDisplayFolderPicker,
-                              base::Unretained(app_view_), title));
-  }
-
-  void OnSetCursorPos(int x, int y) {
-    VLOG(1) << "In IPC OnSetCursorPos: " << x << ", " << y;
-    ui_task_runner_->PostTask(FROM_HERE,
-                              base::Bind(&ChromeAppViewAsh::OnSetCursorPos,
-                                         base::Unretained(app_view_), x, y));
-  }
-
-  void OnImeCancelComposition() {
-    ui_task_runner_->PostTask(
-        FROM_HERE, base::Bind(&ChromeAppViewAsh::OnImeCancelComposition,
-                              base::Unretained(app_view_)));
-  }
-
-  void OnImeTextInputClientChanged(
-      const std::vector<int32_t>& input_scopes,
-      const std::vector<metro_viewer::CharacterBounds>& character_bounds) {
-    ui_task_runner_->PostTask(
-        FROM_HERE, base::Bind(&ChromeAppViewAsh::OnImeUpdateTextInputClient,
-                              base::Unretained(app_view_), input_scopes,
-                              character_bounds));
-  }
-
-  scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner_;
-  ChromeAppViewAsh* app_view_;
-};
-
-void RunMessageLoop(winui::Core::ICoreDispatcher* dispatcher) {
-  // We're entering a nested message loop, let's allow dispatching
-  // tasks while we're in there.
-  base::MessageLoop::current()->SetNestableTasksAllowed(true);
-
-  // Enter main core message loop. There are several ways to exit it
-  // Nicely:
-  // 1 - User action like ALT-F4.
-  // 2 - Calling ICoreApplicationExit::Exit().
-  // 3-  Posting WM_CLOSE to the core window.
-  dispatcher->ProcessEvents(
-      winui::Core::CoreProcessEventsOption
-          ::CoreProcessEventsOption_ProcessUntilQuit);
-
-  // Wind down the thread's chrome message loop.
-  base::MessageLoop::current()->QuitWhenIdle();
-}
-
-// Helper to return the state of the shift/control/alt keys.
-uint32_t GetKeyboardEventFlags() {
-  uint32_t flags = 0;
-  if (ui::win::IsShiftPressed())
-    flags |= ui::EF_SHIFT_DOWN;
-  if (ui::win::IsCtrlPressed())
-    flags |= ui::EF_CONTROL_DOWN;
-  if (ui::win::IsAltPressed())
-    flags |= ui::EF_ALT_DOWN;
-  return flags;
-}
-
-bool LaunchChromeBrowserProcess(const wchar_t* additional_parameters,
-                                winapp::Activation::IActivatedEventArgs* args) {
-  if (args) {
-    DVLOG(1) << __FUNCTION__ << ":" << ::GetCommandLineW();
-    winapp::Activation::ActivationKind activation_kind;
-    CheckHR(args->get_Kind(&activation_kind));
-
-    DVLOG(1) << __FUNCTION__ << ", activation_kind=" << activation_kind;
-
-    if (activation_kind == winapp::Activation::ActivationKind_Launch) {
-      mswr::ComPtr<winapp::Activation::ILaunchActivatedEventArgs> launch_args;
-      if (args->QueryInterface(
-              winapp::Activation::IID_ILaunchActivatedEventArgs,
-              &launch_args) == S_OK) {
-        DVLOG(1) << "Activate: ActivationKind_Launch";
-        mswrw::HString launch_args_str;
-        launch_args->get_Arguments(launch_args_str.GetAddressOf());
-        base::string16 actual_launch_args(
-            MakeStdWString(launch_args_str.Get()));
-        if (actual_launch_args == win8::kMetroViewerConnectVerb) {
-          DVLOG(1) << __FUNCTION__ << "Not launching chrome server";
-          return true;
-        }
-      }
-    }
-  }
-
-  DVLOG(1) << "Launching chrome server";
-  base::FilePath chrome_exe_path;
-
-  if (!PathService::Get(base::FILE_EXE, &chrome_exe_path))
-    return false;
-
-  base::string16 parameters = L"--silent-launch --connect-to-metro-viewer ";
-  if (additional_parameters)
-    parameters += additional_parameters;
-
-  SHELLEXECUTEINFO sei = { sizeof(sei) };
-  sei.nShow = SW_SHOWNORMAL;
-  sei.lpFile = chrome_exe_path.value().c_str();
-  sei.lpDirectory = L"";
-  sei.lpParameters = parameters.c_str();
-  ::ShellExecuteEx(&sei);
-  return true;
-}
-
-}  // namespace
-
-// This class helps decoding the pointer properties of an event.
-class ChromeAppViewAsh::PointerInfoHandler {
- public:
-  PointerInfoHandler(float metro_dpi_scale, float win32_dpi_scale)
-      : x_(0),
-        y_(0),
-        wheel_delta_(0),
-        pointer_id_(0),
-        update_kind_(winui::Input::PointerUpdateKind_Other),
-        timestamp_(0),
-        mouse_down_flags_(0),
-        is_horizontal_wheel_(0),
-        metro_dpi_scale_(metro_dpi_scale),
-        win32_dpi_scale_(win32_dpi_scale) {}
-
-  HRESULT Init(winui::Core::IPointerEventArgs* args) {
-    HRESULT hr = args->get_CurrentPoint(&pointer_point_);
-    if (FAILED(hr))
-      return hr;
-
-    winfoundtn::Point point;
-    hr = pointer_point_->get_Position(&point);
-    if (FAILED(hr))
-      return hr;
-
-    mswr::ComPtr<winui::Input::IPointerPointProperties> properties;
-    hr = pointer_point_->get_Properties(&properties);
-    if (FAILED(hr))
-      return hr;
-
-    hr = properties->get_PointerUpdateKind(&update_kind_);
-    if (FAILED(hr))
-      return hr;
-
-    hr = properties->get_MouseWheelDelta(&wheel_delta_);
-    if (FAILED(hr))
-      return hr;
-
-    is_horizontal_wheel_ = 0;
-    properties->get_IsHorizontalMouseWheel(&is_horizontal_wheel_);
-
-    // The input coordinates are in DIP based on the metro scale factor.
-    // We want to convert it to DIP based on the win32 scale factor.
-    // We scale the point by the metro scale factor and then scale down
-    // via the win32 scale factor which achieves the needful.
-    gfx::Point dip_point_metro(point.X, point.Y);
-    gfx::Point scaled_point_metro =
-        gfx::ScaleToCeiledPoint(dip_point_metro, metro_dpi_scale_);
-    gfx::Point dip_point_win32 =
-        gfx::ScaleToCeiledPoint(scaled_point_metro, 1.0 / win32_dpi_scale_);
-    x_ = dip_point_win32.x();
-    y_ = dip_point_win32.y();
-
-    pointer_point_->get_Timestamp(&timestamp_);
-    pointer_point_->get_PointerId(&pointer_id_);
-    // Map the OS touch event id to a range allowed by the gesture recognizer.
-    if (IsTouch())
-      pointer_id_ %= ui::MotionEvent::MAX_TOUCH_POINT_COUNT;
-
-    boolean left_button_state;
-    hr = properties->get_IsLeftButtonPressed(&left_button_state);
-    if (FAILED(hr))
-      return hr;
-    if (left_button_state)
-      mouse_down_flags_ |= ui::EF_LEFT_MOUSE_BUTTON;
-
-    boolean right_button_state;
-    hr = properties->get_IsRightButtonPressed(&right_button_state);
-    if (FAILED(hr))
-      return hr;
-    if (right_button_state)
-      mouse_down_flags_ |= ui::EF_RIGHT_MOUSE_BUTTON;
-
-    boolean middle_button_state;
-    hr = properties->get_IsMiddleButtonPressed(&middle_button_state);
-    if (FAILED(hr))
-      return hr;
-    if (middle_button_state)
-      mouse_down_flags_ |= ui::EF_MIDDLE_MOUSE_BUTTON;
-
-    return S_OK;
-  }
-
-  bool IsType(windevs::Input::PointerDeviceType type) const {
-    mswr::ComPtr<windevs::Input::IPointerDevice> pointer_device;
-    CheckHR(pointer_point_->get_PointerDevice(&pointer_device));
-    windevs::Input::PointerDeviceType device_type;
-    CheckHR(pointer_device->get_PointerDeviceType(&device_type));
-    return  (device_type == type);
-  }
-
-  bool IsMouse() const {
-    return IsType(windevs::Input::PointerDeviceType_Mouse);
-  }
-
-  bool IsTouch() const {
-    return IsType(windevs::Input::PointerDeviceType_Touch);
-  }
-
-  int32_t wheel_delta() const { return wheel_delta_; }
-
-  // Identifies the button that changed.
-  ui::EventFlags changed_button() const {
-    switch (update_kind_) {
-      case winui::Input::PointerUpdateKind_LeftButtonPressed:
-        return ui::EF_LEFT_MOUSE_BUTTON;
-      case winui::Input::PointerUpdateKind_LeftButtonReleased:
-        return ui::EF_LEFT_MOUSE_BUTTON;
-      case winui::Input::PointerUpdateKind_RightButtonPressed:
-        return ui::EF_RIGHT_MOUSE_BUTTON;
-      case winui::Input::PointerUpdateKind_RightButtonReleased:
-        return ui::EF_RIGHT_MOUSE_BUTTON;
-      case winui::Input::PointerUpdateKind_MiddleButtonPressed:
-        return ui::EF_MIDDLE_MOUSE_BUTTON;
-      case winui::Input::PointerUpdateKind_MiddleButtonReleased:
-        return ui::EF_MIDDLE_MOUSE_BUTTON;
-      default:
-        return ui::EF_NONE;
-    }
-  }
-
-  uint32_t mouse_down_flags() const { return mouse_down_flags_; }
-
-  int x() const { return x_; }
-  int y() const { return y_; }
-
-  uint32_t pointer_id() const { return pointer_id_; }
-
-  uint64_t timestamp() const { return timestamp_; }
-
-  winui::Input::PointerUpdateKind update_kind() const { return update_kind_; }
-
-  bool is_horizontal_wheel() const { return !!is_horizontal_wheel_; }
-
- private:
-  int x_;
-  int y_;
-  int wheel_delta_;
-  uint32_t pointer_id_;
-  winui::Input::PointerUpdateKind update_kind_;
-  mswr::ComPtr<winui::Input::IPointerPoint> pointer_point_;
-  uint64_t timestamp_;
-
-  // Bitmask of ui::EventFlags corresponding to the buttons that are currently
-  // down.
-  uint32_t mouse_down_flags_;
-
-  // Set to true for a horizontal wheel message.
-  boolean is_horizontal_wheel_;
-
-  // The metro device scale factor as reported by the winrt interfaces.
-  float metro_dpi_scale_;
-  // The win32 dpi scale which is queried via GetDeviceCaps. Please refer to
-  // ui/gfx/win/dpi.cc for more information.
-  float win32_dpi_scale_;
-
-  DISALLOW_COPY_AND_ASSIGN(PointerInfoHandler);
-};
-
-ChromeAppViewAsh::ChromeAppViewAsh()
-    : mouse_down_flags_(ui::EF_NONE),
-      ui_channel_(nullptr),
-      core_window_hwnd_(NULL),
-      metro_dpi_scale_(0),
-      win32_dpi_scale_(0),
-      last_cursor_(NULL),
-      channel_listener_(NULL) {
-  DVLOG(1) << __FUNCTION__;
-  globals.previous_state =
-      winapp::Activation::ApplicationExecutionState_NotRunning;
-}
-
-ChromeAppViewAsh::~ChromeAppViewAsh() {
-  DVLOG(1) << __FUNCTION__;
-}
-
-IFACEMETHODIMP
-ChromeAppViewAsh::Initialize(winapp::Core::ICoreApplicationView* view) {
-  view_ = view;
-  DVLOG(1) << __FUNCTION__;
-  HRESULT hr = view_->add_Activated(mswr::Callback<ActivatedHandler>(
-      this, &ChromeAppViewAsh::OnActivate).Get(),
-      &activated_token_);
-  CheckHR(hr);
-  return hr;
-}
-
-IFACEMETHODIMP
-ChromeAppViewAsh::SetWindow(winui::Core::ICoreWindow* window) {
-  window_ = window;
-  DVLOG(1) << __FUNCTION__;
-
-  // Retrieve the native window handle via the interop layer.
-  mswr::ComPtr<ICoreWindowInterop> interop;
-  HRESULT hr = window->QueryInterface(interop.GetAddressOf());
-  CheckHR(hr);
-  hr = interop->get_WindowHandle(&core_window_hwnd_);
-  CheckHR(hr);
-
-  text_service_ = metro_driver::CreateTextService(this, core_window_hwnd_);
-
-  hr = window_->add_SizeChanged(mswr::Callback<SizeChangedHandler>(
-      this, &ChromeAppViewAsh::OnSizeChanged).Get(),
-      &sizechange_token_);
-  CheckHR(hr);
-
-  // Register for pointer and keyboard notifications. We forward
-  // them to the browser process via IPC.
-  hr = window_->add_PointerMoved(mswr::Callback<PointerEventHandler>(
-      this, &ChromeAppViewAsh::OnPointerMoved).Get(),
-      &pointermoved_token_);
-  CheckHR(hr);
-
-  hr = window_->add_PointerPressed(mswr::Callback<PointerEventHandler>(
-      this, &ChromeAppViewAsh::OnPointerPressed).Get(),
-      &pointerpressed_token_);
-  CheckHR(hr);
-
-  hr = window_->add_PointerReleased(mswr::Callback<PointerEventHandler>(
-      this, &ChromeAppViewAsh::OnPointerReleased).Get(),
-      &pointerreleased_token_);
-  CheckHR(hr);
-
-  hr = window_->add_KeyDown(mswr::Callback<KeyEventHandler>(
-      this, &ChromeAppViewAsh::OnKeyDown).Get(),
-      &keydown_token_);
-  CheckHR(hr);
-
-  hr = window_->add_KeyUp(mswr::Callback<KeyEventHandler>(
-      this, &ChromeAppViewAsh::OnKeyUp).Get(),
-      &keyup_token_);
-  CheckHR(hr);
-
-  mswr::ComPtr<winui::Core::ICoreDispatcher> dispatcher;
-  hr = window_->get_Dispatcher(dispatcher.GetAddressOf());
-  CheckHR(hr, "Get Dispatcher failed.");
-
-  mswr::ComPtr<winui::Core::ICoreAcceleratorKeys> accelerator_keys;
-  hr = dispatcher.CopyTo(__uuidof(winui::Core::ICoreAcceleratorKeys),
-                         reinterpret_cast<void**>(
-                            accelerator_keys.GetAddressOf()));
-  CheckHR(hr, "QI for ICoreAcceleratorKeys failed.");
-  hr = accelerator_keys->add_AcceleratorKeyActivated(
-      mswr::Callback<AcceleratorKeyEventHandler>(
-          this, &ChromeAppViewAsh::OnAcceleratorKeyDown).Get(),
-      &accel_keydown_token_);
-  CheckHR(hr);
-
-  hr = window_->add_PointerWheelChanged(mswr::Callback<PointerEventHandler>(
-      this, &ChromeAppViewAsh::OnWheel).Get(),
-      &wheel_token_);
-  CheckHR(hr);
-
-  hr = window_->add_CharacterReceived(mswr::Callback<CharEventHandler>(
-      this, &ChromeAppViewAsh::OnCharacterReceived).Get(),
-      &character_received_token_);
-  CheckHR(hr);
-
-  hr = window_->add_Activated(mswr::Callback<WindowActivatedHandler>(
-      this, &ChromeAppViewAsh::OnWindowActivated).Get(),
-      &window_activated_token_);
-  CheckHR(hr);
-
-  if (base::win::GetVersion() >= base::win::VERSION_WIN8) {
-    // Register for edge gesture notifications only for Windows 8 and above.
-    mswr::ComPtr<winui::Input::IEdgeGestureStatics> edge_gesture_statics;
-    hr = winrt_utils::CreateActivationFactory(
-        RuntimeClass_Windows_UI_Input_EdgeGesture,
-        edge_gesture_statics.GetAddressOf());
-    CheckHR(hr);
-
-    mswr::ComPtr<winui::Input::IEdgeGesture> edge_gesture;
-    hr = edge_gesture_statics->GetForCurrentView(&edge_gesture);
-    CheckHR(hr);
-
-    hr = edge_gesture->add_Completed(mswr::Callback<EdgeEventHandler>(
-        this, &ChromeAppViewAsh::OnEdgeGestureCompleted).Get(),
-        &edgeevent_token_);
-    CheckHR(hr);
-  }
-
-  // By initializing the direct 3D swap chain with the corewindow
-  // we can now directly blit to it from the browser process.
-  direct3d_helper_.Initialize(window);
-  DVLOG(1) << "Initialized Direct3D.";
-
-  // On Windows 8+ the WinRT interface IDisplayProperties which we use to get
-  // device scale factor does not return the correct values in metro mode.
-  // To workaround this we retrieve the device scale factor via the win32 way
-  // and scale input coordinates accordingly to pass them in DIP to chrome.
-  // TODO(ananta). Investigate and fix.
-  metro_dpi_scale_ = GetModernUIScale();
-  win32_dpi_scale_ = gfx::GetDPIScale();
-  DVLOG(1) << "Metro Scale is " << metro_dpi_scale_;
-  DVLOG(1) << "Win32 Scale is " << win32_dpi_scale_;
-  return S_OK;
-}
-
-IFACEMETHODIMP
-ChromeAppViewAsh::Load(HSTRING entryPoint) {
-  // On Win7 |entryPoint| is NULL.
-  DVLOG(1) << __FUNCTION__;
-  return S_OK;
-}
-
-IFACEMETHODIMP
-ChromeAppViewAsh::Run() {
-  DVLOG(1) << __FUNCTION__;
-  mswr::ComPtr<winui::Core::ICoreDispatcher> dispatcher;
-  HRESULT hr = window_->get_Dispatcher(dispatcher.GetAddressOf());
-  CheckHR(hr, "Dispatcher failed.");
-
-  // Create the IPC channel IO thread. It needs to out-live the ChannelProxy.
-  io_thread_.reset(new base::Thread("metro_IO_thread"));
-  base::Thread::Options options;
-  options.message_loop_type = base::MessageLoop::TYPE_IO;
-  io_thread_->StartWithOptions(options);
-
-  ChromeChannelListener ui_channel_listener(&ui_loop_, this);
-  channel_listener_ = &ui_channel_listener;
-
-  // We can't do anything until the Chrome browser IPC channel is initialized.
-  // Lazy initialization in a timer.
-  ui_loop_.PostDelayedTask(FROM_HERE,
-      base::Bind(base::IgnoreResult(&ChromeAppViewAsh::StartChromeOSMode),
-                 base::Unretained(this)),
-      base::TimeDelta::FromMilliseconds(kChromeChannelPollTimerMs));
-
-  // Post the task that'll do the inner Metro message pumping to it.
-  ui_loop_.PostTask(FROM_HERE, base::Bind(&RunMessageLoop, dispatcher.Get()));
-  ui_loop_.Run();
-
-  io_thread_.reset(NULL);
-  ui_channel_.reset(NULL);
-  channel_listener_ = NULL;
-
-  DVLOG(0) << "ProcessEvents done, hr=" << hr;
-  return hr;
-}
-
-IFACEMETHODIMP
-ChromeAppViewAsh::Uninitialize() {
-  DVLOG(1) << __FUNCTION__;
-  metro_driver::RemoveImePopupObserver(this);
-  input_source_.reset();
-  text_service_.reset();
-  window_ = nullptr;
-  view_ = nullptr;
-  core_window_hwnd_ = NULL;
-  return S_OK;
-}
-
-// static
-HRESULT ChromeAppViewAsh::Unsnap() {
-  mswr::ComPtr<winui::ViewManagement::IApplicationViewStatics> view_statics;
-  HRESULT hr = winrt_utils::CreateActivationFactory(
-      RuntimeClass_Windows_UI_ViewManagement_ApplicationView,
-      view_statics.GetAddressOf());
-  CheckHR(hr);
-
-  winui::ViewManagement::ApplicationViewState state =
-      winui::ViewManagement::ApplicationViewState_FullScreenLandscape;
-  hr = view_statics->get_Value(&state);
-  CheckHR(hr);
-
-  if (state == winui::ViewManagement::ApplicationViewState_Snapped) {
-    boolean success = FALSE;
-    hr = view_statics->TryUnsnap(&success);
-
-    if (FAILED(hr) || !success) {
-      LOG(ERROR) << "Failed to unsnap. Error 0x" << hr;
-      if (SUCCEEDED(hr))
-        hr = E_UNEXPECTED;
-    }
-  }
-  return hr;
-}
-
-void ChromeAppViewAsh::OnActivateDesktop(const base::FilePath& file_path,
-                                         bool ash_exit) {
-  DVLOG(1) << "ChannelAppViewAsh::OnActivateDesktop\n";
-
-  if (ash_exit) {
-    // As we are the top level window, the exiting is done async so we manage
-    // to execute  the entire function including the final Send().
-    OnMetroExit(TERMINATE_USING_KEY_SEQUENCE);
-  }
-
-  // We are just executing delegate_execute here without parameters. Assumption
-  // here is that this process will be reused by shell when asking for
-  // IExecuteCommand interface.
-
-  // TODO(shrikant): Consolidate ShellExecuteEx with SEE_MASK_FLAG_LOG_USAGE
-  // and place it metro.h or similar accessible file from all code code paths
-  // using this function.
-  SHELLEXECUTEINFO sei = { sizeof(sei) };
-  sei.fMask = SEE_MASK_FLAG_LOG_USAGE;
-  sei.nShow = SW_SHOWNORMAL;
-  sei.lpFile = file_path.value().c_str();
-  sei.lpParameters = NULL;
-  if (!ash_exit)
-    sei.fMask |= SEE_MASK_NOCLOSEPROCESS;
-  ::ShellExecuteExW(&sei);
-  if (!ash_exit) {
-    ::TerminateProcess(sei.hProcess, 0);
-    ::CloseHandle(sei.hProcess);
-  }
-}
-
-void ChromeAppViewAsh::OnOpenURLOnDesktop(const base::FilePath& shortcut,
-                                          const base::string16& url) {
-  base::FilePath::StringType file = shortcut.value();
-  SHELLEXECUTEINFO sei = { sizeof(sei) };
-  sei.fMask = SEE_MASK_FLAG_LOG_USAGE;
-  sei.nShow = SW_SHOWNORMAL;
-  sei.lpFile = file.c_str();
-  sei.lpDirectory = L"";
-  sei.lpParameters = url.c_str();
-  ShellExecuteEx(&sei);
-}
-
-void ChromeAppViewAsh::OnSetCursor(HCURSOR cursor) {
-  ::SetCursor(cursor);
-  last_cursor_ = cursor;
-}
-
-void ChromeAppViewAsh::OnDisplayFileOpenDialog(
-    const base::string16& title,
-    const base::string16& filter,
-    const base::FilePath& default_path,
-    bool allow_multiple_files) {
-  DVLOG(1) << __FUNCTION__;
-
-  // The OpenFilePickerSession instance is deleted when we receive a
-  // callback from the OpenFilePickerSession class about the completion of the
-  // operation.
-  FilePickerSessionBase* file_picker_ =
-      new OpenFilePickerSession(this,
-                                title,
-                                filter,
-                                default_path,
-                                allow_multiple_files);
-  file_picker_->Run();
-}
-
-void ChromeAppViewAsh::OnDisplayFileSaveAsDialog(
-    const MetroViewerHostMsg_SaveAsDialogParams& params) {
-  DVLOG(1) << __FUNCTION__;
-
-  // The SaveFilePickerSession instance is deleted when we receive a
-  // callback from the SaveFilePickerSession class about the completion of the
-  // operation.
-  FilePickerSessionBase* file_picker_ =
-      new SaveFilePickerSession(this, params);
-  file_picker_->Run();
-}
-
-void ChromeAppViewAsh::OnDisplayFolderPicker(const base::string16& title) {
-  DVLOG(1) << __FUNCTION__;
-  // The FolderPickerSession instance is deleted when we receive a
-  // callback from the FolderPickerSession class about the completion of the
-  // operation.
-  FilePickerSessionBase* file_picker_ = new FolderPickerSession(this, title);
-  file_picker_->Run();
-}
-
-void ChromeAppViewAsh::OnSetCursorPos(int x, int y) {
-  if (ui_channel_) {
-    ::SetCursorPos(x, y);
-    DVLOG(1) << "In UI OnSetCursorPos: " << x << ", " << y;
-    ui_channel_->Send(new MetroViewerHostMsg_SetCursorPosAck());
-    // Generate a fake mouse move which matches the SetCursor coordinates as
-    // the browser expects to receive a mouse move for these coordinates.
-    // It is not clear why we don't receive a real mouse move in response to
-    // the SetCursorPos calll above.
-    ui_channel_->Send(new MetroViewerHostMsg_MouseMoved(x, y, 0));
-  }
-}
-
-void ChromeAppViewAsh::OnOpenFileCompleted(
-    OpenFilePickerSession* open_file_picker,
-    bool success) {
-  DVLOG(1) << __FUNCTION__;
-  DVLOG(1) << "Success: " << success;
-  if (ui_channel_) {
-    if (open_file_picker->allow_multi_select()) {
-      ui_channel_->Send(new MetroViewerHostMsg_MultiFileOpenDone(
-          success, open_file_picker->filenames()));
-    } else {
-      ui_channel_->Send(new MetroViewerHostMsg_FileOpenDone(
-          success, base::FilePath(open_file_picker->result())));
-    }
-  }
-  delete open_file_picker;
-}
-
-void ChromeAppViewAsh::OnSaveFileCompleted(
-    SaveFilePickerSession* save_file_picker,
-    bool success) {
-  DVLOG(1) << __FUNCTION__;
-  DVLOG(1) << "Success: " << success;
-  if (ui_channel_) {
-    ui_channel_->Send(new MetroViewerHostMsg_FileSaveAsDone(
-        success,
-        base::FilePath(save_file_picker->result()),
-        save_file_picker->filter_index()));
-  }
-  delete save_file_picker;
-}
-
-void ChromeAppViewAsh::OnFolderPickerCompleted(
-    FolderPickerSession* folder_picker,
-    bool success) {
-  DVLOG(1) << __FUNCTION__;
-  DVLOG(1) << "Success: " << success;
-  if (ui_channel_) {
-    ui_channel_->Send(new MetroViewerHostMsg_SelectFolderDone(
-        success,
-        base::FilePath(folder_picker->result())));
-  }
-  delete folder_picker;
-}
-
-void ChromeAppViewAsh::OnImeCancelComposition() {
-  if (!text_service_)
-    return;
-  text_service_->CancelComposition();
-}
-
-void ChromeAppViewAsh::OnImeUpdateTextInputClient(
-    const std::vector<int32_t>& input_scopes,
-    const std::vector<metro_viewer::CharacterBounds>& character_bounds) {
-  if (!text_service_)
-    return;
-  text_service_->OnDocumentChanged(input_scopes, character_bounds);
-}
-
-void ChromeAppViewAsh::OnImePopupChanged(ImePopupObserver::EventType event) {
-  if (!ui_channel_)
-    return;
-  switch (event) {
-    case ImePopupObserver::kPopupShown:
-      ui_channel_->Send(new MetroViewerHostMsg_ImeCandidatePopupChanged(true));
-      return;
-    case ImePopupObserver::kPopupHidden:
-      ui_channel_->Send(new MetroViewerHostMsg_ImeCandidatePopupChanged(false));
-      return;
-    case ImePopupObserver::kPopupUpdated:
-      // TODO(kochi): Support this event for W3C IME API proposal.
-      // See crbug.com/238585.
-      return;
-    default:
-      NOTREACHED() << "unknown event type: " << event;
-      return;
-  }
-}
-
-// Function to Exit metro chrome cleanly. If we are in the foreground
-// then we try and exit by sending an Alt+F4 key combination to the core
-// window which ensures that the chrome application tile does not show up in
-// the running metro apps list on the top left corner.
-void ChromeAppViewAsh::OnMetroExit(MetroTerminateMethod method) {
-  if (base::win::GetVersion() >= base::win::VERSION_WIN8) {
-    HWND core_window = core_window_hwnd();
-    if (method == TERMINATE_USING_KEY_SEQUENCE && core_window != NULL &&
-        core_window == ::GetForegroundWindow()) {
-      DVLOG(1) << "We are in the foreground. Exiting via Alt F4";
-      SendKeySequence(VK_F4, ALT);
-      if (ui_channel_)
-        ui_channel_->Close();
-    } else {
-      globals.app_exit->Exit();
-    }
-  } else {
-    if (ui_channel_)
-      ui_channel_->Close();
-
-    HWND core_window = core_window_hwnd();
-    ::PostMessage(core_window, WM_CLOSE, 0, 0);
-
-    globals.app_exit->Exit();
-  }
-}
-
-void ChromeAppViewAsh::OnInputSourceChanged() {
-  if (!input_source_)
-    return;
-
-  DCHECK(ui_channel_);
-
-  LANGID langid = 0;
-  bool is_ime = false;
-  if (!input_source_->GetActiveSource(&langid, &is_ime)) {
-    LOG(ERROR) << "GetActiveSource failed";
-    return;
-  }
-  ui_channel_->Send(new MetroViewerHostMsg_ImeInputSourceChanged(langid,
-                                                                 is_ime));
-}
-
-void ChromeAppViewAsh::OnCompositionChanged(
-    const base::string16& text,
-    int32_t selection_start,
-    int32_t selection_end,
-    const std::vector<metro_viewer::UnderlineInfo>& underlines) {
-  ui_channel_->Send(new MetroViewerHostMsg_ImeCompositionChanged(
-      text, selection_start, selection_end, underlines));
-}
-
-void ChromeAppViewAsh::OnTextCommitted(const base::string16& text) {
-  ui_channel_->Send(new MetroViewerHostMsg_ImeTextCommitted(text));
-}
-
-void ChromeAppViewAsh::SendMouseButton(int x,
-                                       int y,
-                                       int extra,
-                                       ui::EventType event_type,
-                                       uint32_t flags,
-                                       ui::EventFlags changed_button,
-                                       bool is_horizontal_wheel) {
-  if (!ui_channel_)
-    return;
-  MetroViewerHostMsg_MouseButtonParams params;
-  params.x = static_cast<int32_t>(x);
-  params.y = static_cast<int32_t>(y);
-  params.extra = static_cast<int32_t>(extra);
-  params.event_type = event_type;
-  params.flags = static_cast<int32_t>(flags);
-  params.changed_button = changed_button;
-  params.is_horizontal_wheel = is_horizontal_wheel;
-  ui_channel_->Send(new MetroViewerHostMsg_MouseButton(params));
-}
-
-void ChromeAppViewAsh::GenerateMouseEventFromMoveIfNecessary(
-    const PointerInfoHandler& pointer) {
-  ui::EventType event_type;
-  // For aura we want the flags to include the button that was released, thus
-  // we or the old and new.
-  uint32_t mouse_down_flags = pointer.mouse_down_flags() | mouse_down_flags_;
-  mouse_down_flags_ = pointer.mouse_down_flags();
-  switch (pointer.update_kind()) {
-    case winui::Input::PointerUpdateKind_LeftButtonPressed:
-    case winui::Input::PointerUpdateKind_RightButtonPressed:
-    case winui::Input::PointerUpdateKind_MiddleButtonPressed:
-      event_type = ui::ET_MOUSE_PRESSED;
-      break;
-    case winui::Input::PointerUpdateKind_LeftButtonReleased:
-    case winui::Input::PointerUpdateKind_RightButtonReleased:
-    case winui::Input::PointerUpdateKind_MiddleButtonReleased:
-      event_type = ui::ET_MOUSE_RELEASED;
-      break;
-    default:
-      return;
-  }
-  SendMouseButton(pointer.x(), pointer.y(), 0, event_type,
-                  mouse_down_flags | GetKeyboardEventFlags(),
-                  pointer.changed_button(), pointer.is_horizontal_wheel());
-}
-
-HRESULT ChromeAppViewAsh::OnActivate(
-    winapp::Core::ICoreApplicationView*,
-    winapp::Activation::IActivatedEventArgs* args) {
-  DVLOG(1) << __FUNCTION__;
-  // Note: If doing more work in this function, you migth need to call
-  // get_PreviousExecutionState() and skip the work if  the result is
-  // ApplicationExecutionState_Running and globals.previous_state is too.
-  args->get_PreviousExecutionState(&globals.previous_state);
-  DVLOG(1) << "Previous Execution State: " << globals.previous_state;
-
-  winapp::Activation::ActivationKind activation_kind;
-  CheckHR(args->get_Kind(&activation_kind));
-  DVLOG(1) << "Activation kind: " << activation_kind;
-
-  if (activation_kind == winapp::Activation::ActivationKind_Search)
-    HandleSearchRequest(args);
-  else if (activation_kind == winapp::Activation::ActivationKind_Protocol)
-    HandleProtocolRequest(args);
-  else
-    LaunchChromeBrowserProcess(NULL, args);
-  // We call ICoreWindow::Activate after the handling for the search/protocol
-  // requests because Chrome can be launched to handle a search request which
-  // in turn launches the chrome browser process in desktop mode via
-  // ShellExecute. If we call ICoreWindow::Activate before this, then
-  // Windows kills the metro chrome process when it calls ShellExecute. Seems
-  // to be a bug.
-  window_->Activate();
-  return S_OK;
-}
-
-HRESULT ChromeAppViewAsh::OnPointerMoved(winui::Core::ICoreWindow* sender,
-                                         winui::Core::IPointerEventArgs* args) {
-  if (!ui_channel_)
-    return S_OK;
-
-  PointerInfoHandler pointer(metro_dpi_scale_, win32_dpi_scale_);
-  HRESULT hr = pointer.Init(args);
-  if (FAILED(hr))
-    return hr;
-
-  if (pointer.IsMouse()) {
-    // If the mouse was moved towards the charms or the OS specific section,
-    // the cursor may change from what the browser last set. Restore it here.
-    if (::GetCursor() != last_cursor_)
-      SetCursor(last_cursor_);
-
-    GenerateMouseEventFromMoveIfNecessary(pointer);
-    ui_channel_->Send(new MetroViewerHostMsg_MouseMoved(
-        pointer.x(),
-        pointer.y(),
-        mouse_down_flags_ | GetKeyboardEventFlags()));
-  } else {
-    DCHECK(pointer.IsTouch());
-    ui_channel_->Send(new MetroViewerHostMsg_TouchMoved(pointer.x(),
-                                                        pointer.y(),
-                                                        pointer.timestamp(),
-                                                        pointer.pointer_id()));
-  }
-  return S_OK;
-}
-
-// NOTE: From experimentation, it seems like Metro only sends a PointerPressed
-// event for the first button pressed and the last button released in a sequence
-// of mouse events.
-// For example, a sequence of LEFT_DOWN, RIGHT_DOWN, LEFT_UP, RIGHT_UP results
-// only in PointerPressed(LEFT)/PointerReleased(RIGHT) events. Intermediary
-// presses and releases are tracked in OnPointMoved().
-HRESULT ChromeAppViewAsh::OnPointerPressed(
-    winui::Core::ICoreWindow* sender,
-    winui::Core::IPointerEventArgs* args) {
-  if (!ui_channel_)
-    return S_OK;
-
-  PointerInfoHandler pointer(metro_dpi_scale_, win32_dpi_scale_);
-  HRESULT hr = pointer.Init(args);
-  if (FAILED(hr))
-    return hr;
-
-  if (pointer.IsMouse()) {
-    mouse_down_flags_ = pointer.mouse_down_flags();
-    SendMouseButton(pointer.x(), pointer.y(), 0, ui::ET_MOUSE_PRESSED,
-                    mouse_down_flags_ | GetKeyboardEventFlags(),
-                    pointer.changed_button(), pointer.is_horizontal_wheel());
-  } else {
-    DCHECK(pointer.IsTouch());
-    ui_channel_->Send(new MetroViewerHostMsg_TouchDown(pointer.x(),
-                                                       pointer.y(),
-                                                       pointer.timestamp(),
-                                                       pointer.pointer_id()));
-  }
-  return S_OK;
-}
-
-HRESULT ChromeAppViewAsh::OnPointerReleased(
-    winui::Core::ICoreWindow* sender,
-    winui::Core::IPointerEventArgs* args) {
-  if (!ui_channel_)
-    return S_OK;
-
-  PointerInfoHandler pointer(metro_dpi_scale_, win32_dpi_scale_);
-  HRESULT hr = pointer.Init(args);
-  if (FAILED(hr))
-    return hr;
-
-  if (pointer.IsMouse()) {
-    mouse_down_flags_ = ui::EF_NONE;
-    SendMouseButton(pointer.x(), pointer.y(), 0, ui::ET_MOUSE_RELEASED,
-                    static_cast<uint32_t>(pointer.changed_button()) |
-                        GetKeyboardEventFlags(),
-                    pointer.changed_button(), pointer.is_horizontal_wheel());
-  } else {
-    DCHECK(pointer.IsTouch());
-    ui_channel_->Send(new MetroViewerHostMsg_TouchUp(pointer.x(),
-                                                     pointer.y(),
-                                                     pointer.timestamp(),
-                                                     pointer.pointer_id()));
-  }
-  return S_OK;
-}
-
-HRESULT ChromeAppViewAsh::OnWheel(
-    winui::Core::ICoreWindow* sender,
-    winui::Core::IPointerEventArgs* args) {
-  if (!ui_channel_)
-    return S_OK;
-
-  PointerInfoHandler pointer(metro_dpi_scale_, win32_dpi_scale_);
-  HRESULT hr = pointer.Init(args);
-  if (FAILED(hr))
-    return hr;
-  DCHECK(pointer.IsMouse());
-  SendMouseButton(pointer.x(), pointer.y(), pointer.wheel_delta(),
-                  ui::ET_MOUSEWHEEL, GetKeyboardEventFlags(), ui::EF_NONE,
-                  pointer.is_horizontal_wheel());
-  return S_OK;
-}
-
-HRESULT ChromeAppViewAsh::OnKeyDown(
-    winui::Core::ICoreWindow* sender,
-    winui::Core::IKeyEventArgs* args) {
-  if (!ui_channel_)
-    return S_OK;
-
-  winsys::VirtualKey virtual_key;
-  HRESULT hr = args->get_VirtualKey(&virtual_key);
-  if (FAILED(hr))
-    return hr;
-  winui::Core::CorePhysicalKeyStatus status;
-  hr = args->get_KeyStatus(&status);
-  if (FAILED(hr))
-    return hr;
-
-  ui_channel_->Send(new MetroViewerHostMsg_KeyDown(virtual_key,
-                                                   status.RepeatCount,
-                                                   status.ScanCode,
-                                                   GetKeyboardEventFlags()));
-  return S_OK;
-}
-
-HRESULT ChromeAppViewAsh::OnKeyUp(
-    winui::Core::ICoreWindow* sender,
-    winui::Core::IKeyEventArgs* args) {
-  if (!ui_channel_)
-    return S_OK;
-
-  winsys::VirtualKey virtual_key;
-  HRESULT hr = args->get_VirtualKey(&virtual_key);
-  if (FAILED(hr))
-    return hr;
-  winui::Core::CorePhysicalKeyStatus status;
-  hr = args->get_KeyStatus(&status);
-  if (FAILED(hr))
-    return hr;
-
-  ui_channel_->Send(new MetroViewerHostMsg_KeyUp(virtual_key,
-                                                 status.RepeatCount,
-                                                 status.ScanCode,
-                                                 GetKeyboardEventFlags()));
-  return S_OK;
-}
-
-HRESULT ChromeAppViewAsh::OnAcceleratorKeyDown(
-    winui::Core::ICoreDispatcher* sender,
-    winui::Core::IAcceleratorKeyEventArgs* args) {
-  if (!ui_channel_)
-    return S_OK;
-
-  winsys::VirtualKey virtual_key;
-  HRESULT hr = args->get_VirtualKey(&virtual_key);
-  if (FAILED(hr))
-    return hr;
-  winui::Core::CorePhysicalKeyStatus status;
-  hr = args->get_KeyStatus(&status);
-  if (FAILED(hr))
-    return hr;
-
-  winui::Core::CoreAcceleratorKeyEventType event_type;
-  hr = args->get_EventType(&event_type);
-  if (FAILED(hr))
-    return hr;
-
-  uint32_t keyboard_flags = GetKeyboardEventFlags();
-
-  switch (event_type) {
-    case winui::Core::CoreAcceleratorKeyEventType_SystemCharacter:
-      ui_channel_->Send(new MetroViewerHostMsg_Character(virtual_key,
-                                                         status.RepeatCount,
-                                                         status.ScanCode,
-                                                         keyboard_flags));
-      break;
-
-    case winui::Core::CoreAcceleratorKeyEventType_SystemKeyDown:
-      // Don't send the Alt + F4 combination to Chrome as this is intended to
-      // shut the metro environment down. Reason we check for Control here is
-      // Windows does not shutdown metro if Ctrl is pressed along with Alt F4.
-      // Other key combinations with Alt F4 shutdown metro.
-      if ((virtual_key == VK_F4) && ((keyboard_flags & ui::EF_ALT_DOWN) &&
-          !(keyboard_flags & ui::EF_CONTROL_DOWN)))
-        return S_OK;
-      // Don't send the EF_ALT_DOWN modifier along with the IPC message for
-      // the Alt or F10 key. The accelerator for VKEY_MENU is registered
-      // without modifiers in Chrome for historical reasons. Not sending the
-      // EF_ALT_DOWN modifier ensures that the accelerator is processed
-      // correctly.
-      if (virtual_key == winsys::VirtualKey_Menu)
-        keyboard_flags &= ~ui::EF_ALT_DOWN;
-      ui_channel_->Send(new MetroViewerHostMsg_KeyDown(virtual_key,
-                                                       status.RepeatCount,
-                                                       status.ScanCode,
-                                                       keyboard_flags));
-      break;
-
-    case winui::Core::CoreAcceleratorKeyEventType_SystemKeyUp:
-      ui_channel_->Send(new MetroViewerHostMsg_KeyUp(virtual_key,
-                                                     status.RepeatCount,
-                                                     status.ScanCode,
-                                                     keyboard_flags));
-      break;
-
-    default:
-      break;
-  }
-  return S_OK;
-}
-
-HRESULT ChromeAppViewAsh::OnCharacterReceived(
-  winui::Core::ICoreWindow* sender,
-  winui::Core::ICharacterReceivedEventArgs* args) {
-  if (!ui_channel_)
-    return S_OK;
-
-  unsigned int char_code = 0;
-  HRESULT hr = args->get_KeyCode(&char_code);
-  if (FAILED(hr))
-    return hr;
-
-  winui::Core::CorePhysicalKeyStatus status;
-  hr = args->get_KeyStatus(&status);
-  if (FAILED(hr))
-    return hr;
-
-  ui_channel_->Send(new MetroViewerHostMsg_Character(char_code,
-                                                     status.RepeatCount,
-                                                     status.ScanCode,
-                                                     GetKeyboardEventFlags()));
-  return S_OK;
-}
-
-HRESULT ChromeAppViewAsh::OnWindowActivated(
-    winui::Core::ICoreWindow* sender,
-    winui::Core::IWindowActivatedEventArgs* args) {
-  if (!ui_channel_)
-    return S_OK;
-
-  if (args) {
-    winui::Core::CoreWindowActivationState state;
-    HRESULT hr = args->get_WindowActivationState(&state);
-    if (FAILED(hr))
-      return hr;
-
-    // Treat both full activation (Ash was reopened from the Start Screen or
-    // from any other Metro entry point in Windows) and pointer activation
-    // (user clicked back in Ash after using another app on another monitor)
-    // the same.
-    if (state == winui::Core::CoreWindowActivationState_CodeActivated ||
-        state == winui::Core::CoreWindowActivationState_PointerActivated) {
-      ui_channel_->Send(new MetroViewerHostMsg_WindowActivated(false));
-    }
-  } else {
-    // On Windows 7, we force a repaint when the window is activated.
-    ui_channel_->Send(new MetroViewerHostMsg_WindowActivated(true));
-  }
-  if (text_service_)
-    text_service_->OnWindowActivated();
-  return S_OK;
-}
-
-HRESULT ChromeAppViewAsh::HandleSearchRequest(
-    winapp::Activation::IActivatedEventArgs* args) {
-  mswr::ComPtr<winapp::Activation::ISearchActivatedEventArgs> search_args;
-  CheckHR(args->QueryInterface(
-          winapp::Activation::IID_ISearchActivatedEventArgs, &search_args));
-
-  if (!ui_channel_) {
-    DVLOG(1) << "Launched to handle search request";
-    LaunchChromeBrowserProcess(L"--windows8-search", args);
-  }
-
-  mswrw::HString search_string;
-  CheckHR(search_args->get_QueryText(search_string.GetAddressOf()));
-  base::string16 search_text(MakeStdWString(search_string.Get()));
-
-  ui_loop_.PostTask(FROM_HERE,
-                    base::Bind(&ChromeAppViewAsh::OnSearchRequest,
-                    base::Unretained(this),
-                    search_text));
-  return S_OK;
-}
-
-HRESULT ChromeAppViewAsh::HandleProtocolRequest(
-    winapp::Activation::IActivatedEventArgs* args) {
-  DVLOG(1) << __FUNCTION__;
-  if (!ui_channel_)
-    DVLOG(1) << "Launched to handle url request";
-
-  mswr::ComPtr<winapp::Activation::IProtocolActivatedEventArgs>
-      protocol_args;
-  CheckHR(args->QueryInterface(
-          winapp::Activation::IID_IProtocolActivatedEventArgs,
-          &protocol_args));
-
-  mswr::ComPtr<winfoundtn::IUriRuntimeClass> uri;
-  protocol_args->get_Uri(&uri);
-  mswrw::HString url;
-  uri->get_AbsoluteUri(url.GetAddressOf());
-  base::string16 actual_url(MakeStdWString(url.Get()));
-  DVLOG(1) << "Received url request: " << actual_url;
-
-  ui_loop_.PostTask(FROM_HERE,
-                    base::Bind(&ChromeAppViewAsh::OnNavigateToUrl,
-                               base::Unretained(this),
-                               actual_url));
-  return S_OK;
-}
-
-HRESULT ChromeAppViewAsh::OnEdgeGestureCompleted(
-    winui::Input::IEdgeGesture* gesture,
-    winui::Input::IEdgeGestureEventArgs* args) {
-  if (ui_channel_)
-    ui_channel_->Send(new MetroViewerHostMsg_EdgeGesture());
-  return S_OK;
-}
-
-void ChromeAppViewAsh::OnSearchRequest(const base::string16& search_string) {
-  if (ui_channel_)
-    ui_channel_->Send(new MetroViewerHostMsg_SearchRequest(search_string));
-}
-
-void ChromeAppViewAsh::OnNavigateToUrl(const base::string16& url) {
-  if (ui_channel_)
-    ui_channel_->Send(new MetroViewerHostMsg_OpenURL(url));
-}
-
-HRESULT ChromeAppViewAsh::OnSizeChanged(winui::Core::ICoreWindow* sender,
-    winui::Core::IWindowSizeChangedEventArgs* args) {
-  if (!window_ || !ui_channel_) {
-    return S_OK;
-  }
-
-  // winui::Core::IWindowSizeChangedEventArgs args->Size appears to return
-  // scaled values under HiDPI. We will instead use GetWindowRect() which
-  // should always return values in Pixels.
-  RECT rect = {0};
-  ::GetWindowRect(core_window_hwnd_, &rect);
-
-  uint32_t cx = static_cast<uint32_t>(rect.right - rect.left);
-  uint32_t cy = static_cast<uint32_t>(rect.bottom - rect.top);
-
-  DVLOG(1) << "Window size changed: width=" << cx << ", height=" << cy;
-  ui_channel_->Send(new MetroViewerHostMsg_WindowSizeChanged(cx, cy));
-  return S_OK;
-}
-
-void ChromeAppViewAsh::StartChromeOSMode() {
-  static int ms_elapsed = 0;
-
-  if (!IPC::Channel::IsNamedServerInitialized(
-          win8::kMetroViewerIPCChannelName) && ms_elapsed < 10000) {
-    ms_elapsed += 100;
-    ui_loop_.PostDelayedTask(FROM_HERE,
-        base::Bind(base::IgnoreResult(&ChromeAppViewAsh::StartChromeOSMode),
-                   base::Unretained(this)),
-        base::TimeDelta::FromMilliseconds(kChromeChannelPollTimerMs));
-    return;
-  }
-
-  if (!IPC::Channel::IsNamedServerInitialized(
-          win8::kMetroViewerIPCChannelName)) {
-    DVLOG(1) << "Failed to connect to chrome channel : "
-             << win8::kMetroViewerIPCChannelName;
-    DVLOG(1) << "Exiting. Elapsed time :" << ms_elapsed;
-    PostMessage(core_window_hwnd_, WM_CLOSE, 0, 0);
-    return;
-  }
-
-  DVLOG(1) << "Found channel : " << win8::kMetroViewerIPCChannelName;
-
-  DCHECK(channel_listener_);
-
-  // In Aura mode we create an IPC channel to the browser, then ask it to
-  // connect to us.
-  ui_channel_ =
-      IPC::ChannelProxy::Create(win8::kMetroViewerIPCChannelName,
-                                IPC::Channel::MODE_NAMED_CLIENT,
-                                channel_listener_,
-                                io_thread_->task_runner());
-  DVLOG(1) << "Created channel proxy";
-
-  // Upon receipt of the MetroViewerHostMsg_SetTargetSurface message the
-  // browser will use D3D from the browser process to present to our Window.
-  ui_channel_->Send(new MetroViewerHostMsg_SetTargetSurface(
-      gfx::NativeViewId(core_window_hwnd_),
-      win32_dpi_scale_));
-  DVLOG(1) << "ICoreWindow sent " << core_window_hwnd_;
-
-  // Send an initial size message so that the Ash root window host gets sized
-  // correctly.
-  RECT rect = {0};
-  ::GetWindowRect(core_window_hwnd_, &rect);
-  ui_channel_->Send(
-      new MetroViewerHostMsg_WindowSizeChanged(rect.right - rect.left,
-                                               rect.bottom - rect.top));
-
-  input_source_ = metro_driver::InputSource::Create();
-  if (input_source_) {
-    input_source_->AddObserver(this);
-    // Send an initial input source.
-    OnInputSourceChanged();
-  }
-
-  // Start receiving IME popup window notifications.
-  metro_driver::AddImePopupObserver(this);
-
-  DVLOG(1) << "Channel setup complete";
-}
-
-///////////////////////////////////////////////////////////////////////////////
-
-ChromeAppViewFactory::ChromeAppViewFactory(
-    winapp::Core::ICoreApplication* icore_app) {
-  mswr::ComPtr<winapp::Core::ICoreApplication> core_app(icore_app);
-  mswr::ComPtr<winapp::Core::ICoreApplicationExit> app_exit;
-  CheckHR(core_app.As(&app_exit));
-  globals.app_exit = app_exit.Detach();
-}
-
-IFACEMETHODIMP
-ChromeAppViewFactory::CreateView(winapp::Core::IFrameworkView** view) {
-  *view = mswr::Make<ChromeAppViewAsh>().Detach();
-  return (*view) ? S_OK :  E_OUTOFMEMORY;
-}
diff --git a/win8/metro_driver/chrome_app_view_ash.h b/win8/metro_driver/chrome_app_view_ash.h
deleted file mode 100644
index ffe1d7e..0000000
--- a/win8/metro_driver/chrome_app_view_ash.h
+++ /dev/null
@@ -1,262 +0,0 @@
-// Copyright (c) 2012 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 WIN8_METRO_DRIVER_CHROME_APP_VIEW_ASH_H_
-#define WIN8_METRO_DRIVER_CHROME_APP_VIEW_ASH_H_
-
-#include <stdint.h>
-#include <windows.applicationmodel.core.h>
-#include <windows.ui.core.h>
-#include <windows.ui.input.h>
-#include <windows.ui.viewmanagement.h>
-
-#include "base/memory/scoped_ptr.h"
-#include "base/message_loop/message_loop.h"
-#include "base/strings/string16.h"
-#include "base/threading/thread.h"
-#include "ipc/ipc_listener.h"
-#include "ui/events/event_constants.h"
-#include "win8/metro_driver/direct3d_helper.h"
-#include "win8/metro_driver/ime/ime_popup_observer.h"
-#include "win8/metro_driver/ime/input_source_observer.h"
-#include "win8/metro_driver/ime/text_service_delegate.h"
-
-namespace base {
-class FilePath;
-}
-
-namespace IPC {
-class Listener;
-class ChannelProxy;
-}
-
-namespace metro_driver {
-class InputSource;
-class TextService;
-}
-
-namespace metro_viewer {
-struct CharacterBounds;
-struct UnderlineInfo;
-}
-
-class OpenFilePickerSession;
-class SaveFilePickerSession;
-class FolderPickerSession;
-class FilePickerSessionBase;
-
-struct MetroViewerHostMsg_SaveAsDialogParams;
-
-enum MetroTerminateMethod {
-  TERMINATE_USING_KEY_SEQUENCE = 1,
-  TERMINATE_USING_PROCESS_EXIT = 2,
-};
-
-class ChromeAppViewAsh
-    : public mswr::RuntimeClass<winapp::Core::IFrameworkView>,
-      public metro_driver::ImePopupObserver,
-      public metro_driver::InputSourceObserver,
-      public metro_driver::TextServiceDelegate {
- public:
-  ChromeAppViewAsh();
-  ~ChromeAppViewAsh() override;
-
-  // IViewProvider overrides.
-  IFACEMETHOD(Initialize)(winapp::Core::ICoreApplicationView* view) override;
-  IFACEMETHOD(SetWindow)(winui::Core::ICoreWindow* window) override;
-  IFACEMETHOD(Load)(HSTRING entryPoint) override;
-  IFACEMETHOD(Run)() override;
-  IFACEMETHOD(Uninitialize)() override;
-
-  // Helper function to unsnap the chrome metro app if it is snapped.
-  // Returns S_OK on success.
-  static HRESULT Unsnap();
-
-  void OnActivateDesktop(const base::FilePath& file_path, bool ash_exit);
-  void OnOpenURLOnDesktop(const base::FilePath& shortcut,
-                          const base::string16& url);
-  void OnSetCursor(HCURSOR cursor);
-  void OnDisplayFileOpenDialog(const base::string16& title,
-                               const base::string16& filter,
-                               const base::FilePath& default_path,
-                               bool allow_multiple_files);
-  void OnDisplayFileSaveAsDialog(
-      const MetroViewerHostMsg_SaveAsDialogParams& params);
-  void OnDisplayFolderPicker(const base::string16& title);
-  void OnSetCursorPos(int x, int y);
-
-  // This function is invoked when the open file operation completes. The
-  // result of the operation is passed in along with the OpenFilePickerSession
-  // instance which is deleted after we read the required information from
-  // the OpenFilePickerSession class.
-  void OnOpenFileCompleted(OpenFilePickerSession* open_file_picker,
-                           bool success);
-
-  // This function is invoked when the save file operation completes. The
-  // result of the operation is passed in along with the SaveFilePickerSession
-  // instance which is deleted after we read the required information from
-  // the SaveFilePickerSession class.
-  void OnSaveFileCompleted(SaveFilePickerSession* save_file_picker,
-                           bool success);
-
-  // This function is invoked when the folder picker operation completes. The
-  // result of the operation is passed in along with the FolderPickerSession
-  // instance which is deleted after we read the required information from
-  // the FolderPickerSession class.
-  void OnFolderPickerCompleted(FolderPickerSession* folder_picker,
-                               bool success);
-
-  void OnImeCancelComposition();
-  void OnImeUpdateTextInputClient(
-      const std::vector<int32_t>& input_scopes,
-      const std::vector<metro_viewer::CharacterBounds>& character_bounds);
-
-  void OnMetroExit(MetroTerminateMethod method);
-
-  HWND core_window_hwnd() const { return  core_window_hwnd_; }
-
-
- private:
-  class PointerInfoHandler;
-
-  // ImePopupObserver overrides.
-  void OnImePopupChanged(ImePopupObserver::EventType event) override;
-
-  // InputSourceObserver overrides.
-  void OnInputSourceChanged() override;
-
-  // TextServiceDelegate overrides.
-  void OnCompositionChanged(
-      const base::string16& text,
-      int32_t selection_start,
-      int32_t selection_end,
-      const std::vector<metro_viewer::UnderlineInfo>& underlines) override;
-  void OnTextCommitted(const base::string16& text) override;
-
-  // Convenience for sending a MetroViewerHostMsg_MouseButton with the specified
-  // parameters.
-  void SendMouseButton(int x,
-                       int y,
-                       int extra,
-                       ui::EventType event_type,
-                       uint32_t flags,
-                       ui::EventFlags changed_button,
-                       bool is_horizontal_wheel);
-
-  // Win8 only generates a mouse press for the initial button that goes down and
-  // a release when the last button is released. Any intermediary presses (or
-  // releases) do not result in a new press/release event. Instead a move is
-  // generated with the winui::Input::PointerUpdateKind identifying what
-  // changed. This function generates the necessary intermediary events (as
-  // necessary).
-  void GenerateMouseEventFromMoveIfNecessary(const PointerInfoHandler& pointer);
-
-  HRESULT OnActivate(winapp::Core::ICoreApplicationView* view,
-                     winapp::Activation::IActivatedEventArgs* args);
-
-  HRESULT OnPointerMoved(winui::Core::ICoreWindow* sender,
-                         winui::Core::IPointerEventArgs* args);
-
-  HRESULT OnPointerPressed(winui::Core::ICoreWindow* sender,
-                           winui::Core::IPointerEventArgs* args);
-
-  HRESULT OnPointerReleased(winui::Core::ICoreWindow* sender,
-                            winui::Core::IPointerEventArgs* args);
-
-  HRESULT OnWheel(winui::Core::ICoreWindow* sender,
-                  winui::Core::IPointerEventArgs* args);
-
-  HRESULT OnKeyDown(winui::Core::ICoreWindow* sender,
-                    winui::Core::IKeyEventArgs* args);
-
-  HRESULT OnKeyUp(winui::Core::ICoreWindow* sender,
-                  winui::Core::IKeyEventArgs* args);
-
-  // Invoked for system keys like Alt, etc.
-  HRESULT OnAcceleratorKeyDown(winui::Core::ICoreDispatcher* sender,
-                               winui::Core::IAcceleratorKeyEventArgs* args);
-
-  HRESULT OnCharacterReceived(winui::Core::ICoreWindow* sender,
-                              winui::Core::ICharacterReceivedEventArgs* args);
-
-  HRESULT OnWindowActivated(winui::Core::ICoreWindow* sender,
-                            winui::Core::IWindowActivatedEventArgs* args);
-
-  // Helper to handle search requests received via the search charm in ASH.
-  HRESULT HandleSearchRequest(winapp::Activation::IActivatedEventArgs* args);
-  // Helper to handle http/https url requests in ASH.
-  HRESULT HandleProtocolRequest(winapp::Activation::IActivatedEventArgs* args);
-
-  HRESULT OnEdgeGestureCompleted(winui::Input::IEdgeGesture* gesture,
-                                 winui::Input::IEdgeGestureEventArgs* args);
-
-  // Tasks posted to the UI thread to initiate the search/url navigation
-  // requests.
-  void OnSearchRequest(const base::string16& search_string);
-  void OnNavigateToUrl(const base::string16& url);
-
-  HRESULT OnSizeChanged(winui::Core::ICoreWindow* sender,
-                        winui::Core::IWindowSizeChangedEventArgs* args);
-
-  // This function checks if the Chrome browser channel is initialized. If yes
-  // then it goes ahead and starts up the viewer in Chrome OS mode. If not it
-  // posts a delayed task and checks again. It does this for a duration of 10
-  // seconds and then bails.
-  void StartChromeOSMode();
-
-  mswr::ComPtr<winui::Core::ICoreWindow> window_;
-  mswr::ComPtr<winapp::Core::ICoreApplicationView> view_;
-  EventRegistrationToken activated_token_;
-  EventRegistrationToken pointermoved_token_;
-  EventRegistrationToken pointerpressed_token_;
-  EventRegistrationToken pointerreleased_token_;
-  EventRegistrationToken wheel_token_;
-  EventRegistrationToken keydown_token_;
-  EventRegistrationToken keyup_token_;
-  EventRegistrationToken character_received_token_;
-  EventRegistrationToken accel_keydown_token_;
-  EventRegistrationToken accel_keyup_token_;
-  EventRegistrationToken window_activated_token_;
-  EventRegistrationToken sizechange_token_;
-  EventRegistrationToken edgeevent_token_;
-
-  // Keep state about which button is currently down, if any, as PointerMoved
-  // events do not contain that state, but Ash's MouseEvents need it. Value is
-  // as a bitmask of ui::EventFlags.
-  uint32_t mouse_down_flags_;
-
-  // Set the D3D swap chain and nothing else.
-  metro_driver::Direct3DHelper direct3d_helper_;
-
-  // The IPC channel IO thread.
-  scoped_ptr<base::Thread> io_thread_;
-
-  // The channel to Chrome, in particular to the MetroViewerProcessHost.
-  scoped_ptr<IPC::ChannelProxy> ui_channel_;
-
-  // The actual window behind the view surface.
-  HWND core_window_hwnd_;
-
-  // UI message loop to allow message passing into this thread.
-  base::MessageLoopForUI ui_loop_;
-
-  // For IME support.
-  scoped_ptr<metro_driver::InputSource> input_source_;
-  scoped_ptr<metro_driver::TextService> text_service_;
-
-  // The metro device scale factor as reported by the winrt interfaces.
-  float metro_dpi_scale_;
-  // The win32 dpi scale which is queried via GetDeviceCaps. Please refer to
-  // ui/gfx/win/dpi.cc for more information.
-  float win32_dpi_scale_;
-
-  // The cursor set by the chroem browser process.
-  HCURSOR last_cursor_;
-
-  // Pointer to the channel listener for the channel between the viewer and
-  // the browser.
-  IPC::Listener* channel_listener_;
-};
-
-#endif  // WIN8_METRO_DRIVER_CHROME_APP_VIEW_ASH_H_
diff --git a/win8/metro_driver/file_picker.cc b/win8/metro_driver/file_picker.cc
deleted file mode 100644
index 708b338c..0000000
--- a/win8/metro_driver/file_picker.cc
+++ /dev/null
@@ -1,622 +0,0 @@
-// Copyright (c) 2012 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 "stdafx.h"
-#include "win8/metro_driver/file_picker.h"
-
-#include <stddef.h>
-#include <stdint.h>
-#include <windows.storage.pickers.h>
-
-#include "base/bind.h"
-#include "base/files/file_path.h"
-#include "base/logging.h"
-#include "base/macros.h"
-#include "base/message_loop/message_loop.h"
-#include "base/strings/string_util.h"
-#include "base/synchronization/waitable_event.h"
-#include "base/win/metro.h"
-#include "base/win/scoped_comptr.h"
-#include "win8/metro_driver/chrome_app_view.h"
-#include "win8/metro_driver/winrt_utils.h"
-
-namespace {
-
-namespace winstorage = ABI::Windows::Storage;
-typedef winfoundtn::Collections::IVector<HSTRING> StringVectorItf;
-
-// TODO(siggi): Complete this implementation and move it to a common place.
-class StringVectorImpl : public mswr::RuntimeClass<StringVectorItf> {
- public:
-  ~StringVectorImpl() {
-    std::for_each(strings_.begin(), strings_.end(), ::WindowsDeleteString);
-  }
-
-  HRESULT RuntimeClassInitialize(const std::vector<base::string16>& list) {
-    for (size_t i = 0; i < list.size(); ++i)
-      strings_.push_back(MakeHString(list[i]));
-
-    return S_OK;
-  }
-
-  // IVector<HSTRING> implementation.
-  STDMETHOD(GetAt)(unsigned index, HSTRING* item) {
-    if (index >= strings_.size())
-      return E_INVALIDARG;
-
-    return ::WindowsDuplicateString(strings_[index], item);
-  }
-  STDMETHOD(get_Size)(unsigned *size) {
-    if (strings_.size() > UINT_MAX)
-      return E_UNEXPECTED;
-    *size = static_cast<unsigned>(strings_.size());
-    return S_OK;
-  }
-  STDMETHOD(GetView)(winfoundtn::Collections::IVectorView<HSTRING> **view) {
-    return E_NOTIMPL;
-  }
-  STDMETHOD(IndexOf)(HSTRING value, unsigned *index, boolean *found) {
-    return E_NOTIMPL;
-  }
-
-  // write methods
-  STDMETHOD(SetAt)(unsigned index, HSTRING item) {
-    return E_NOTIMPL;
-  }
-  STDMETHOD(InsertAt)(unsigned index, HSTRING item) {
-    return E_NOTIMPL;
-  }
-  STDMETHOD(RemoveAt)(unsigned index) {
-    return E_NOTIMPL;
-  }
-  STDMETHOD(Append)(HSTRING item) {
-    return E_NOTIMPL;
-  }
-  STDMETHOD(RemoveAtEnd)() {
-    return E_NOTIMPL;
-  }
-  STDMETHOD(Clear)() {
-    return E_NOTIMPL;
-  }
-
- private:
-  std::vector<HSTRING> strings_;
-};
-
-class FilePickerSessionBase {
- public:
-  // Creates a file picker for open_file_name.
-  explicit FilePickerSessionBase(OPENFILENAME* open_file_name);
-
-  // Runs the picker, returns true on success.
-  bool Run();
-
- protected:
-  // Creates, configures and starts a file picker.
-  // If the HRESULT returned is a failure code the file picker has not started,
-  // so no callbacks should be expected.
-  virtual HRESULT StartFilePicker() = 0;
-
-  // The parameters to our picker.
-  OPENFILENAME* open_file_name_;
-  // The event Run waits on.
-  base::WaitableEvent event_;
-  // True iff a file picker has successfully finished.
-  bool success_;
-
- private:
-  // Initiate a file picker, must be called on the metro dispatcher's thread.
-  void DoFilePicker();
-
-  DISALLOW_COPY_AND_ASSIGN(FilePickerSessionBase);
-};
-
-class OpenFilePickerSession : public FilePickerSessionBase {
- public:
-  explicit OpenFilePickerSession(OPENFILENAME* open_file_name);
-
- private:
-  HRESULT StartFilePicker() override;
-
-  typedef winfoundtn::IAsyncOperation<winstorage::StorageFile*>
-      SingleFileAsyncOp;
-  typedef winfoundtn::Collections::IVectorView<
-      winstorage::StorageFile*> StorageFileVectorCollection;
-  typedef winfoundtn::IAsyncOperation<StorageFileVectorCollection*>
-      MultiFileAsyncOp;
-
-  // Called asynchronously when a single file picker is done.
-  HRESULT SinglePickerDone(SingleFileAsyncOp* async, AsyncStatus status);
-
-  // Called asynchronously when a multi file picker is done.
-  HRESULT MultiPickerDone(MultiFileAsyncOp* async, AsyncStatus status);
-
-  // Composes a multi-file result string suitable for returning to a
-  // from a storage file collection.
-  static HRESULT ComposeMultiFileResult(StorageFileVectorCollection* files,
-                                        base::string16* result);
- private:
-  DISALLOW_COPY_AND_ASSIGN(OpenFilePickerSession);
-};
-
-class SaveFilePickerSession : public FilePickerSessionBase {
- public:
-  explicit SaveFilePickerSession(OPENFILENAME* open_file_name);
-
- private:
-  HRESULT StartFilePicker() override;
-
-  typedef winfoundtn::IAsyncOperation<winstorage::StorageFile*>
-      SaveFileAsyncOp;
-
-  // Called asynchronously when the save file picker is done.
-  HRESULT FilePickerDone(SaveFileAsyncOp* async, AsyncStatus status);
-};
-
-FilePickerSessionBase::FilePickerSessionBase(OPENFILENAME* open_file_name)
-    : open_file_name_(open_file_name),
-      event_(true, false),
-      success_(false) {
-}
-
-bool FilePickerSessionBase::Run() {
-  DCHECK(globals.appview_msg_loop != NULL);
-
-  // Post the picker request over to the metro thread.
-  bool posted = globals.appview_msg_loop->PostTask(FROM_HERE,
-      base::Bind(&FilePickerSessionBase::DoFilePicker, base::Unretained(this)));
-  if (!posted)
-    return false;
-
-  // Wait for the file picker to complete.
-  event_.Wait();
-
-  return success_;
-}
-
-void FilePickerSessionBase::DoFilePicker() {
-  // The file picker will fail if spawned from a snapped application,
-  // so let's attempt to unsnap first if we're in that state.
-  HRESULT hr = ChromeAppView::Unsnap();
-  if (FAILED(hr)) {
-    LOG(ERROR) << "Failed to unsnap for file picker, error 0x" << hr;
-  }
-
-  if (SUCCEEDED(hr))
-    hr = StartFilePicker();
-
-  if (FAILED(hr)) {
-    LOG(ERROR) << "Failed to start file picker, error 0x"
-               << std::hex << hr;
-
-    event_.Signal();
-  }
-}
-
-OpenFilePickerSession::OpenFilePickerSession(OPENFILENAME* open_file_name)
-    : FilePickerSessionBase(open_file_name) {
-}
-
-HRESULT OpenFilePickerSession::SinglePickerDone(SingleFileAsyncOp* async,
-                                                AsyncStatus status) {
-  if (status == Completed) {
-    mswr::ComPtr<winstorage::IStorageFile> file;
-    HRESULT hr = async->GetResults(file.GetAddressOf());
-
-    if (file) {
-      mswr::ComPtr<winstorage::IStorageItem> storage_item;
-      if (SUCCEEDED(hr))
-        hr = file.As(&storage_item);
-
-      mswrw::HString file_path;
-      if (SUCCEEDED(hr))
-        hr = storage_item->get_Path(file_path.GetAddressOf());
-
-      if (SUCCEEDED(hr)) {
-        UINT32 path_len = 0;
-        const wchar_t* path_str =
-            ::WindowsGetStringRawBuffer(file_path.Get(), &path_len);
-
-        // If the selected file name is longer than the supplied buffer,
-        // we return false as per GetOpenFileName documentation.
-        if (path_len < open_file_name_->nMaxFile) {
-          base::wcslcpy(open_file_name_->lpstrFile,
-                        path_str,
-                        open_file_name_->nMaxFile);
-          success_ = true;
-        }
-      }
-    } else {
-      LOG(ERROR) << "NULL IStorageItem";
-    }
-  } else {
-    LOG(ERROR) << "Unexpected async status " << static_cast<int>(status);
-  }
-
-  event_.Signal();
-
-  return S_OK;
-}
-
-HRESULT OpenFilePickerSession::MultiPickerDone(MultiFileAsyncOp* async,
-                                                 AsyncStatus status) {
-  if (status == Completed) {
-    mswr::ComPtr<StorageFileVectorCollection> files;
-    HRESULT hr = async->GetResults(files.GetAddressOf());
-
-    if (files) {
-      base::string16 result;
-      if (SUCCEEDED(hr))
-        hr = ComposeMultiFileResult(files.Get(), &result);
-
-      if (SUCCEEDED(hr)) {
-        if (result.size() + 1 < open_file_name_->nMaxFile) {
-          // Because the result has embedded nulls, we must memcpy.
-          memcpy(open_file_name_->lpstrFile,
-                 result.c_str(),
-                 (result.size() + 1) * sizeof(result[0]));
-          success_ = true;
-        }
-      }
-    } else {
-      LOG(ERROR) << "NULL StorageFileVectorCollection";
-    }
-  } else {
-    LOG(ERROR) << "Unexpected async status " << static_cast<int>(status);
-  }
-
-  event_.Signal();
-
-  return S_OK;
-}
-
-HRESULT OpenFilePickerSession::StartFilePicker() {
-  DCHECK(globals.appview_msg_loop->BelongsToCurrentThread());
-  DCHECK(open_file_name_ != NULL);
-
-  mswrw::HStringReference class_name(
-      RuntimeClass_Windows_Storage_Pickers_FileOpenPicker);
-
-  // Create the file picker.
-  mswr::ComPtr<winstorage::Pickers::IFileOpenPicker> picker;
-  HRESULT hr = ::Windows::Foundation::ActivateInstance(
-      class_name.Get(), picker.GetAddressOf());
-  CheckHR(hr);
-
-  // Set the file type filter
-  mswr::ComPtr<winfoundtn::Collections::IVector<HSTRING>> filter;
-  hr = picker->get_FileTypeFilter(filter.GetAddressOf());
-  if (FAILED(hr))
-    return hr;
-
-  if (open_file_name_->lpstrFilter == NULL) {
-    hr = filter->Append(mswrw::HStringReference(L"*").Get());
-    if (FAILED(hr))
-      return hr;
-  } else {
-    // The filter is a concatenation of zero terminated string pairs,
-    // where each pair is {description, extension}. The concatenation ends
-    // with a zero length string - e.g. a double zero terminator.
-    const wchar_t* walk = open_file_name_->lpstrFilter;
-    while (*walk != L'\0') {
-      // Walk past the description.
-      walk += wcslen(walk) + 1;
-
-      // We should have an extension, but bail on malformed filters.
-      if (*walk == L'\0')
-        break;
-
-      // There can be a single extension, or a list of semicolon-separated ones.
-      std::vector<base::string16> extensions_win32_style = base::SplitString(
-          walk, L";", base::KEEP_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
-
-      // Metro wants suffixes only, not patterns.
-      mswrw::HString extension;
-      for (size_t i = 0; i < extensions_win32_style.size(); ++i) {
-        if (extensions_win32_style[i] == L"*.*") {
-          // The wildcard filter is "*" for Metro. The string "*.*" produces
-          // an "invalid parameter" error.
-          hr = extension.Set(L"*");
-        } else {
-          // Metro wants suffixes only, not patterns.
-          base::string16 ext =
-              base::FilePath(extensions_win32_style[i]).Extension();
-          if ((ext.size() < 2) ||
-              (ext.find_first_of(L"*?") != base::string16::npos)) {
-            continue;
-          }
-          hr = extension.Set(ext.c_str());
-        }
-        if (SUCCEEDED(hr))
-          hr = filter->Append(extension.Get());
-        if (FAILED(hr))
-          return hr;
-      }
-
-      // Walk past the extension.
-      walk += wcslen(walk) + 1;
-    }
-  }
-
-  // Spin up a single or multi picker as appropriate.
-  if (open_file_name_->Flags & OFN_ALLOWMULTISELECT) {
-    mswr::ComPtr<MultiFileAsyncOp> completion;
-    hr = picker->PickMultipleFilesAsync(&completion);
-    if (FAILED(hr))
-      return hr;
-
-    // Create the callback method.
-    typedef winfoundtn::IAsyncOperationCompletedHandler<
-        StorageFileVectorCollection*> HandlerDoneType;
-    mswr::ComPtr<HandlerDoneType> handler(mswr::Callback<HandlerDoneType>(
-        this, &OpenFilePickerSession::MultiPickerDone));
-    DCHECK(handler.Get() != NULL);
-    hr = completion->put_Completed(handler.Get());
-
-    return hr;
-  } else {
-    mswr::ComPtr<SingleFileAsyncOp> completion;
-    hr = picker->PickSingleFileAsync(&completion);
-    if (FAILED(hr))
-      return hr;
-
-    // Create the callback method.
-    typedef winfoundtn::IAsyncOperationCompletedHandler<
-        winstorage::StorageFile*> HandlerDoneType;
-    mswr::ComPtr<HandlerDoneType> handler(mswr::Callback<HandlerDoneType>(
-        this, &OpenFilePickerSession::SinglePickerDone));
-    DCHECK(handler.Get() != NULL);
-    hr = completion->put_Completed(handler.Get());
-
-    return hr;
-  }
-}
-
-HRESULT OpenFilePickerSession::ComposeMultiFileResult(
-    StorageFileVectorCollection* files, base::string16* result) {
-  DCHECK(files != NULL);
-  DCHECK(result != NULL);
-
-  // Empty the output string.
-  result->clear();
-
-  unsigned int num_files = 0;
-  HRESULT hr = files->get_Size(&num_files);
-  if (FAILED(hr))
-    return hr;
-
-  // Make sure we return an error on an empty collection.
-  if (num_files == 0) {
-    DLOG(ERROR) << "Empty collection on input.";
-    return E_UNEXPECTED;
-  }
-
-  // This stores the base path that should be the parent of all the files.
-  base::FilePath base_path;
-
-  // Iterate through the collection and append the file paths to the result.
-  for (unsigned int i = 0; i < num_files; ++i) {
-    mswr::ComPtr<winstorage::IStorageFile> file;
-    hr = files->GetAt(i, file.GetAddressOf());
-    if (FAILED(hr))
-      return hr;
-
-    mswr::ComPtr<winstorage::IStorageItem> storage_item;
-    hr = file.As(&storage_item);
-    if (FAILED(hr))
-      return hr;
-
-    mswrw::HString file_path_str;
-    hr = storage_item->get_Path(file_path_str.GetAddressOf());
-    if (FAILED(hr))
-      return hr;
-
-    base::FilePath file_path(MakeStdWString(file_path_str.Get()));
-    if (base_path.empty()) {
-      DCHECK(result->empty());
-      base_path = file_path.DirName();
-
-      // Append the path, including the terminating zero.
-      // We do this only for the first file.
-      result->append(base_path.value().c_str(), base_path.value().size() + 1);
-    }
-    DCHECK(!result->empty());
-    DCHECK(!base_path.empty());
-    DCHECK(base_path == file_path.DirName());
-
-    // Append the base name, including the terminating zero.
-    base::FilePath base_name = file_path.BaseName();
-    result->append(base_name.value().c_str(), base_name.value().size() + 1);
-  }
-
-  DCHECK(!result->empty());
-
-  return S_OK;
-}
-
-SaveFilePickerSession::SaveFilePickerSession(OPENFILENAME* open_file_name)
-    : FilePickerSessionBase(open_file_name) {
-}
-
-HRESULT SaveFilePickerSession::StartFilePicker() {
-  DCHECK(globals.appview_msg_loop->BelongsToCurrentThread());
-  DCHECK(open_file_name_ != NULL);
-
-  mswrw::HStringReference class_name(
-      RuntimeClass_Windows_Storage_Pickers_FileSavePicker);
-
-  // Create the file picker.
-  mswr::ComPtr<winstorage::Pickers::IFileSavePicker> picker;
-  HRESULT hr = ::Windows::Foundation::ActivateInstance(
-      class_name.Get(), picker.GetAddressOf());
-  CheckHR(hr);
-
-  typedef winfoundtn::Collections::IMap<HSTRING, StringVectorItf*>
-      StringVectorMap;
-  mswr::ComPtr<StringVectorMap> choices;
-  hr = picker->get_FileTypeChoices(choices.GetAddressOf());
-  if (FAILED(hr))
-    return hr;
-
-  if (open_file_name_->lpstrFilter) {
-    // The filter is a concatenation of zero terminated string pairs,
-    // where each pair is {description, extension list}. The concatenation ends
-    // with a zero length string - e.g. a double zero terminator.
-    const wchar_t* walk = open_file_name_->lpstrFilter;
-    while (*walk != L'\0') {
-      mswrw::HString description;
-      hr = description.Set(walk);
-      if (FAILED(hr))
-        return hr;
-
-      // Walk past the description.
-      walk += wcslen(walk) + 1;
-
-      // We should have an extension, but bail on malformed filters.
-      if (*walk == L'\0')
-        break;
-
-      // There can be a single extension, or a list of semicolon-separated ones.
-      std::vector<base::string16> extensions_win32_style = base::SplitString(
-          walk, L";", base::KEEP_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
-
-      // Metro wants suffixes only, not patterns.  Also, metro does not support
-      // the all files ("*") pattern in the save picker.
-      std::vector<base::string16> extensions;
-      for (size_t i = 0; i < extensions_win32_style.size(); ++i) {
-        base::string16 ext =
-            base::FilePath(extensions_win32_style[i]).Extension();
-        if ((ext.size() < 2) ||
-            (ext.find_first_of(L"*?") != base::string16::npos))
-          continue;
-        extensions.push_back(ext);
-      }
-
-      if (!extensions.empty()) {
-        // Convert to a Metro collection class.
-        mswr::ComPtr<StringVectorItf> list;
-        hr = mswr::MakeAndInitialize<StringVectorImpl>(
-            list.GetAddressOf(), extensions);
-        if (FAILED(hr))
-          return hr;
-
-        // Finally set the filter.
-        boolean replaced = FALSE;
-        hr = choices->Insert(description.Get(), list.Get(), &replaced);
-        if (FAILED(hr))
-          return hr;
-        DCHECK_EQ(FALSE, replaced);
-      }
-
-      // Walk past the extension(s).
-      walk += wcslen(walk) + 1;
-    }
-  }
-
-  // The save picker requires at least one choice.  Callers are strongly advised
-  // to provide sensible choices.  If none were given, fallback to .dat.
-  uint32_t num_choices = 0;
-  hr = choices->get_Size(&num_choices);
-  if (FAILED(hr))
-    return hr;
-
-  if (num_choices == 0) {
-    mswrw::HString description;
-    // TODO(grt): Get a properly translated string.  This can't be done from
-    // within metro_driver.  Consider preprocessing the filter list in Chrome
-    // land to ensure it has this entry if all others are patterns.  In that
-    // case, this whole block of code can be removed.
-    hr = description.Set(L"Data File");
-    if (FAILED(hr))
-      return hr;
-
-    mswr::ComPtr<StringVectorItf> list;
-    hr = mswr::MakeAndInitialize<StringVectorImpl>(
-        list.GetAddressOf(), std::vector<base::string16>(1, L".dat"));
-    if (FAILED(hr))
-      return hr;
-
-    boolean replaced = FALSE;
-    hr = choices->Insert(description.Get(), list.Get(), &replaced);
-    if (FAILED(hr))
-      return hr;
-    DCHECK_EQ(FALSE, replaced);
-  }
-
-  if (open_file_name_->lpstrFile != NULL) {
-    hr = picker->put_SuggestedFileName(
-        mswrw::HStringReference(
-            const_cast<const wchar_t*>(open_file_name_->lpstrFile)).Get());
-    if (FAILED(hr))
-      return hr;
-  }
-
-  mswr::ComPtr<SaveFileAsyncOp> completion;
-  hr = picker->PickSaveFileAsync(&completion);
-  if (FAILED(hr))
-    return hr;
-
-  // Create the callback method.
-  typedef winfoundtn::IAsyncOperationCompletedHandler<
-      winstorage::StorageFile*> HandlerDoneType;
-  mswr::ComPtr<HandlerDoneType> handler(mswr::Callback<HandlerDoneType>(
-      this, &SaveFilePickerSession::FilePickerDone));
-  DCHECK(handler.Get() != NULL);
-  hr = completion->put_Completed(handler.Get());
-
-  return hr;
-}
-
-HRESULT SaveFilePickerSession::FilePickerDone(SaveFileAsyncOp* async,
-                                              AsyncStatus status) {
-  if (status == Completed) {
-    mswr::ComPtr<winstorage::IStorageFile> file;
-    HRESULT hr = async->GetResults(file.GetAddressOf());
-
-    if (file) {
-      mswr::ComPtr<winstorage::IStorageItem> storage_item;
-      if (SUCCEEDED(hr))
-        hr = file.As(&storage_item);
-
-      mswrw::HString file_path;
-      if (SUCCEEDED(hr))
-        hr = storage_item->get_Path(file_path.GetAddressOf());
-
-      if (SUCCEEDED(hr)) {
-        base::string16 path_str = MakeStdWString(file_path.Get());
-
-        // If the selected file name is longer than the supplied buffer,
-        // we return false as per GetOpenFileName documentation.
-        if (path_str.size() < open_file_name_->nMaxFile) {
-          base::wcslcpy(open_file_name_->lpstrFile,
-                        path_str.c_str(),
-                        open_file_name_->nMaxFile);
-          success_ = true;
-        }
-      }
-    } else {
-      LOG(ERROR) << "NULL IStorageItem";
-    }
-  } else {
-    LOG(ERROR) << "Unexpected async status " << static_cast<int>(status);
-  }
-
-  event_.Signal();
-
-  return S_OK;
-}
-
-}  // namespace
-
-BOOL MetroGetOpenFileName(OPENFILENAME* open_file_name) {
-  OpenFilePickerSession session(open_file_name);
-
-  return session.Run();
-}
-
-BOOL MetroGetSaveFileName(OPENFILENAME* open_file_name) {
-  SaveFilePickerSession session(open_file_name);
-
-  return session.Run();
-}
diff --git a/win8/metro_driver/file_picker.h b/win8/metro_driver/file_picker.h
deleted file mode 100644
index ef56cb39..0000000
--- a/win8/metro_driver/file_picker.h
+++ /dev/null
@@ -1,18 +0,0 @@
-// Copyright (c) 2012 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_UI_METRO_DRIVER_FILE_PICKER_H_
-#define CHROME_BROWSER_UI_METRO_DRIVER_FILE_PICKER_H_
-
-#include <commdlg.h>
-
-// This function behaves similarly to GetOpenFileName, except it uses a
-// Metro file picker to pick a single or multiple file names.
-extern "C" __declspec(dllexport)
-BOOL MetroGetOpenFileName(OPENFILENAME* open_file_name);
-
-extern "C" __declspec(dllexport)
-BOOL MetroGetSaveFileName(OPENFILENAME* open_file_name);
-
-#endif  // CHROME_BROWSER_UI_METRO_DRIVER_FILE_PICKER_H_
-
diff --git a/win8/metro_driver/file_picker_ash.cc b/win8/metro_driver/file_picker_ash.cc
deleted file mode 100644
index 31e699d..0000000
--- a/win8/metro_driver/file_picker_ash.cc
+++ /dev/null
@@ -1,619 +0,0 @@
-// Copyright (c) 2013 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 <stddef.h>
-#include <stdint.h>
-
-#include "stdafx.h"
-#include "win8/metro_driver/file_picker_ash.h"
-
-#include "base/bind.h"
-#include "base/logging.h"
-#include "base/message_loop/message_loop.h"
-#include "base/strings/string_split.h"
-#include "base/strings/string_util.h"
-#include "base/synchronization/waitable_event.h"
-#include "base/win/scoped_comptr.h"
-#include "ui/metro_viewer/metro_viewer_messages.h"
-#include "win8/metro_driver/chrome_app_view_ash.h"
-#include "win8/metro_driver/winrt_utils.h"
-
-namespace {
-
-typedef winfoundtn::Collections::IVector<HSTRING> StringVectorItf;
-
-// TODO(siggi): Complete this implementation and move it to a common place.
-class StringVectorImpl : public mswr::RuntimeClass<StringVectorItf> {
- public:
-  ~StringVectorImpl() override {
-    std::for_each(strings_.begin(), strings_.end(), ::WindowsDeleteString);
-  }
-
-  HRESULT RuntimeClassInitialize(const std::vector<base::string16>& list) {
-    for (size_t i = 0; i < list.size(); ++i)
-      strings_.push_back(MakeHString(list[i]));
-
-    return S_OK;
-  }
-
-  // IVector<HSTRING> implementation.
-  STDMETHOD(GetAt)(unsigned index, HSTRING* item) override {
-    if (index >= strings_.size())
-      return E_INVALIDARG;
-
-    return ::WindowsDuplicateString(strings_[index], item);
-  }
-  STDMETHOD(get_Size)(unsigned* size) override {
-    if (strings_.size() > UINT_MAX)
-      return E_UNEXPECTED;
-    *size = static_cast<unsigned>(strings_.size());
-    return S_OK;
-  }
-  STDMETHOD(GetView)(
-      winfoundtn::Collections::IVectorView<HSTRING>** view) override {
-    return E_NOTIMPL;
-  }
-  STDMETHOD(IndexOf)(HSTRING value, unsigned* index, boolean* found) override {
-    return E_NOTIMPL;
-  }
-
-  // write methods
-  STDMETHOD(SetAt)(unsigned index, HSTRING item) override { return E_NOTIMPL; }
-  STDMETHOD(InsertAt)(unsigned index, HSTRING item) override {
-    return E_NOTIMPL;
-  }
-  STDMETHOD(RemoveAt)(unsigned index) override { return E_NOTIMPL; }
-  STDMETHOD(Append)(HSTRING item) override { return E_NOTIMPL; }
-  STDMETHOD(RemoveAtEnd)() override { return E_NOTIMPL; }
-  STDMETHOD(Clear)() override { return E_NOTIMPL; }
-
- private:
-  std::vector<HSTRING> strings_;
-};
-
-}  // namespace
-
-FilePickerSessionBase::~FilePickerSessionBase() {
-}
-
-bool FilePickerSessionBase::Run() {
-  if (!DoFilePicker())
-    return false;
-  return success_;
-}
-
-FilePickerSessionBase::FilePickerSessionBase(ChromeAppViewAsh* app_view,
-                                             const base::string16& title,
-                                             const base::string16& filter,
-                                             const base::FilePath& default_path)
-    : success_(false),
-      title_(title),
-      filter_(filter),
-      default_path_(default_path),
-      app_view_(app_view) {
-}
-
-bool FilePickerSessionBase::DoFilePicker() {
-  // The file picker will fail if spawned from a snapped application,
-  // so let's attempt to unsnap first if we're in that state.
-  HRESULT hr = ChromeAppViewAsh::Unsnap();
-  if (FAILED(hr)) {
-    LOG(ERROR) << "Failed to unsnap for file picker, error 0x" << hr;
-    return false;
-  }
-  hr = StartFilePicker();
-  if (FAILED(hr)) {
-    LOG(ERROR) << "Failed to start file picker, error 0x"
-               << std::hex << hr;
-    return false;
-  }
-  return true;
-}
-
-OpenFilePickerSession::OpenFilePickerSession(
-    ChromeAppViewAsh* app_view,
-    const base::string16& title,
-    const base::string16& filter,
-    const base::FilePath& default_path,
-    bool allow_multi_select)
-    : FilePickerSessionBase(app_view, title, filter, default_path),
-      allow_multi_select_(allow_multi_select) {
-}
-
-OpenFilePickerSession::~OpenFilePickerSession() {
-}
-
-HRESULT OpenFilePickerSession::SinglePickerDone(SingleFileAsyncOp* async,
-                                                AsyncStatus status) {
-  if (status == Completed) {
-    mswr::ComPtr<winstorage::IStorageFile> file;
-    HRESULT hr = async->GetResults(file.GetAddressOf());
-
-    if (file) {
-      mswr::ComPtr<winstorage::IStorageItem> storage_item;
-      if (SUCCEEDED(hr))
-        hr = file.As(&storage_item);
-
-      mswrw::HString file_path;
-      if (SUCCEEDED(hr))
-        hr = storage_item->get_Path(file_path.GetAddressOf());
-
-      if (SUCCEEDED(hr)) {
-        UINT32 path_len = 0;
-        const wchar_t* path_str =
-            ::WindowsGetStringRawBuffer(file_path.Get(), &path_len);
-
-        result_ = path_str;
-        success_ = true;
-      }
-    } else {
-      LOG(ERROR) << "NULL IStorageItem";
-    }
-  } else {
-    LOG(ERROR) << "Unexpected async status " << static_cast<int>(status);
-  }
-  app_view_->OnOpenFileCompleted(this, success_);
-  return S_OK;
-}
-
-HRESULT OpenFilePickerSession::MultiPickerDone(MultiFileAsyncOp* async,
-                                               AsyncStatus status) {
-  if (status == Completed) {
-    mswr::ComPtr<StorageFileVectorCollection> files;
-    HRESULT hr = async->GetResults(files.GetAddressOf());
-
-    if (files) {
-      base::string16 result;
-      if (SUCCEEDED(hr))
-        hr = ComposeMultiFileResult(files.Get(), &result);
-
-      if (SUCCEEDED(hr)) {
-        success_ = true;
-        // The code below has been copied from the
-        // SelectFileDialogImpl::RunOpenMultiFileDialog function in
-        // select_file_dialog_win.cc.
-        // TODO(ananta)
-        // Consolidate this into a common place.
-        const wchar_t* selection = result.c_str();
-        std::vector<base::FilePath> files;
-
-        while (*selection) {  // Empty string indicates end of list.
-          files.push_back(base::FilePath(selection));
-          // Skip over filename and null-terminator.
-          selection += files.back().value().length() + 1;
-        }
-        if (files.empty()) {
-          success_ = false;
-        } else if (files.size() == 1) {
-          // When there is one file, it contains the path and filename.
-          filenames_ = files;
-        } else if (files.size() > 1) {
-          // Otherwise, the first string is the path, and the remainder are
-          // filenames.
-          std::vector<base::FilePath>::iterator path = files.begin();
-          for (std::vector<base::FilePath>::iterator file = path + 1;
-               file != files.end(); ++file) {
-            filenames_.push_back(path->Append(*file));
-          }
-        }
-      }
-    } else {
-      LOG(ERROR) << "NULL StorageFileVectorCollection";
-    }
-  } else {
-    LOG(ERROR) << "Unexpected async status " << static_cast<int>(status);
-  }
-  app_view_->OnOpenFileCompleted(this, success_);
-  return S_OK;
-}
-
-HRESULT OpenFilePickerSession::StartFilePicker() {
-  mswrw::HStringReference class_name(
-      RuntimeClass_Windows_Storage_Pickers_FileOpenPicker);
-
-  // Create the file picker.
-  mswr::ComPtr<winstorage::Pickers::IFileOpenPicker> picker;
-  HRESULT hr = ::Windows::Foundation::ActivateInstance(
-      class_name.Get(), picker.GetAddressOf());
-  CheckHR(hr);
-
-  // Set the file type filter
-  mswr::ComPtr<winfoundtn::Collections::IVector<HSTRING>> filter;
-  hr = picker->get_FileTypeFilter(filter.GetAddressOf());
-  if (FAILED(hr))
-    return hr;
-
-  if (filter_.empty()) {
-    hr = filter->Append(mswrw::HStringReference(L"*").Get());
-    if (FAILED(hr))
-      return hr;
-  } else {
-    // The filter is a concatenation of zero terminated string pairs,
-    // where each pair is {description, extension}. The concatenation ends
-    // with a zero length string - e.g. a double zero terminator.
-    const wchar_t* walk = filter_.c_str();
-    while (*walk != L'\0') {
-      // Walk past the description.
-      walk += wcslen(walk) + 1;
-
-      // We should have an extension, but bail on malformed filters.
-      if (*walk == L'\0')
-        break;
-
-      // There can be a single extension, or a list of semicolon-separated ones.
-      std::vector<base::string16> extensions_win32_style = base::SplitString(
-          walk, L";", base::KEEP_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
-
-      // Metro wants suffixes only, not patterns.
-      mswrw::HString extension;
-      for (size_t i = 0; i < extensions_win32_style.size(); ++i) {
-        if (extensions_win32_style[i] == L"*.*") {
-          // The wildcard filter is "*" for Metro. The string "*.*" produces
-          // an "invalid parameter" error.
-          hr = extension.Set(L"*");
-        } else {
-          // Metro wants suffixes only, not patterns.
-          base::string16 ext =
-              base::FilePath(extensions_win32_style[i]).Extension();
-          if ((ext.size() < 2) ||
-              (ext.find_first_of(L"*?") != base::string16::npos)) {
-            continue;
-          }
-          hr = extension.Set(ext.c_str());
-        }
-        if (SUCCEEDED(hr))
-          hr = filter->Append(extension.Get());
-        if (FAILED(hr))
-          return hr;
-      }
-
-      // Walk past the extension.
-      walk += wcslen(walk) + 1;
-    }
-  }
-
-  // Spin up a single or multi picker as appropriate.
-  if (allow_multi_select_) {
-    mswr::ComPtr<MultiFileAsyncOp> completion;
-    hr = picker->PickMultipleFilesAsync(&completion);
-    if (FAILED(hr))
-      return hr;
-
-    // Create the callback method.
-    typedef winfoundtn::IAsyncOperationCompletedHandler<
-        StorageFileVectorCollection*> HandlerDoneType;
-    mswr::ComPtr<HandlerDoneType> handler(mswr::Callback<HandlerDoneType>(
-        this, &OpenFilePickerSession::MultiPickerDone));
-    DCHECK(handler.Get() != NULL);
-    hr = completion->put_Completed(handler.Get());
-
-    return hr;
-  } else {
-    mswr::ComPtr<SingleFileAsyncOp> completion;
-    hr = picker->PickSingleFileAsync(&completion);
-    if (FAILED(hr))
-      return hr;
-
-    // Create the callback method.
-    typedef winfoundtn::IAsyncOperationCompletedHandler<
-        winstorage::StorageFile*> HandlerDoneType;
-    mswr::ComPtr<HandlerDoneType> handler(mswr::Callback<HandlerDoneType>(
-        this, &OpenFilePickerSession::SinglePickerDone));
-    DCHECK(handler.Get() != NULL);
-    hr = completion->put_Completed(handler.Get());
-
-    return hr;
-  }
-}
-
-HRESULT OpenFilePickerSession::ComposeMultiFileResult(
-    StorageFileVectorCollection* files, base::string16* result) {
-  DCHECK(files != NULL);
-  DCHECK(result != NULL);
-
-  // Empty the output string.
-  result->clear();
-
-  unsigned int num_files = 0;
-  HRESULT hr = files->get_Size(&num_files);
-  if (FAILED(hr))
-    return hr;
-
-  // Make sure we return an error on an empty collection.
-  if (num_files == 0) {
-    DLOG(ERROR) << "Empty collection on input.";
-    return E_UNEXPECTED;
-  }
-
-  // This stores the base path that should be the parent of all the files.
-  base::FilePath base_path;
-
-  // Iterate through the collection and append the file paths to the result.
-  for (unsigned int i = 0; i < num_files; ++i) {
-    mswr::ComPtr<winstorage::IStorageFile> file;
-    hr = files->GetAt(i, file.GetAddressOf());
-    if (FAILED(hr))
-      return hr;
-
-    mswr::ComPtr<winstorage::IStorageItem> storage_item;
-    hr = file.As(&storage_item);
-    if (FAILED(hr))
-      return hr;
-
-    mswrw::HString file_path_str;
-    hr = storage_item->get_Path(file_path_str.GetAddressOf());
-    if (FAILED(hr))
-      return hr;
-
-    base::FilePath file_path(MakeStdWString(file_path_str.Get()));
-    if (base_path.empty()) {
-      DCHECK(result->empty());
-      base_path = file_path.DirName();
-
-      // Append the path, including the terminating zero.
-      // We do this only for the first file.
-      result->append(base_path.value().c_str(), base_path.value().size() + 1);
-    }
-    DCHECK(!result->empty());
-    DCHECK(!base_path.empty());
-    DCHECK(base_path == file_path.DirName());
-
-    // Append the base name, including the terminating zero.
-    base::FilePath base_name = file_path.BaseName();
-    result->append(base_name.value().c_str(), base_name.value().size() + 1);
-  }
-
-  DCHECK(!result->empty());
-
-  return S_OK;
-}
-
-SaveFilePickerSession::SaveFilePickerSession(
-    ChromeAppViewAsh* app_view,
-    const MetroViewerHostMsg_SaveAsDialogParams& params)
-    : FilePickerSessionBase(app_view,
-                            params.title,
-                            params.filter,
-                            params.suggested_name),
-      filter_index_(params.filter_index) {
-}
-
-int SaveFilePickerSession::filter_index() const {
-  // TODO(ananta)
-  // Add support for returning the correct filter index. This does not work in
-  // regular Chrome metro on trunk as well.
-  // BUG: https://code.google.com/p/chromium/issues/detail?id=172704
-  return filter_index_;
-}
-
-HRESULT SaveFilePickerSession::StartFilePicker() {
-  mswrw::HStringReference class_name(
-      RuntimeClass_Windows_Storage_Pickers_FileSavePicker);
-
-  // Create the file picker.
-  mswr::ComPtr<winstorage::Pickers::IFileSavePicker> picker;
-  HRESULT hr = ::Windows::Foundation::ActivateInstance(
-      class_name.Get(), picker.GetAddressOf());
-  CheckHR(hr);
-
-  typedef winfoundtn::Collections::IMap<HSTRING, StringVectorItf*>
-      StringVectorMap;
-  mswr::ComPtr<StringVectorMap> choices;
-  hr = picker->get_FileTypeChoices(choices.GetAddressOf());
-  if (FAILED(hr))
-    return hr;
-
-  if (!filter_.empty()) {
-    // The filter is a concatenation of zero terminated string pairs,
-    // where each pair is {description, extension list}. The concatenation ends
-    // with a zero length string - e.g. a double zero terminator.
-    const wchar_t* walk = filter_.c_str();
-    while (*walk != L'\0') {
-      mswrw::HString description;
-      hr = description.Set(walk);
-      if (FAILED(hr))
-        return hr;
-
-      // Walk past the description.
-      walk += wcslen(walk) + 1;
-
-      // We should have an extension, but bail on malformed filters.
-      if (*walk == L'\0')
-        break;
-
-      // There can be a single extension, or a list of semicolon-separated ones.
-      std::vector<base::string16> extensions_win32_style = base::SplitString(
-          walk, L";", base::KEEP_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
-
-      // Metro wants suffixes only, not patterns.  Also, metro does not support
-      // the all files ("*") pattern in the save picker.
-      std::vector<base::string16> extensions;
-      for (size_t i = 0; i < extensions_win32_style.size(); ++i) {
-        base::string16 ext =
-            base::FilePath(extensions_win32_style[i]).Extension();
-        if ((ext.size() < 2) ||
-            (ext.find_first_of(L"*?") != base::string16::npos))
-          continue;
-        extensions.push_back(ext);
-      }
-
-      if (!extensions.empty()) {
-        // Convert to a Metro collection class.
-        mswr::ComPtr<StringVectorItf> list;
-        hr = mswr::MakeAndInitialize<StringVectorImpl>(
-            list.GetAddressOf(), extensions);
-        if (FAILED(hr))
-          return hr;
-
-        // Finally set the filter.
-        boolean replaced = FALSE;
-        hr = choices->Insert(description.Get(), list.Get(), &replaced);
-        if (FAILED(hr))
-          return hr;
-        DCHECK_EQ(FALSE, replaced);
-      }
-
-      // Walk past the extension(s).
-      walk += wcslen(walk) + 1;
-    }
-  }
-
-  // The save picker requires at least one choice.  Callers are strongly advised
-  // to provide sensible choices.  If none were given, fallback to .dat.
-  uint32_t num_choices = 0;
-  hr = choices->get_Size(&num_choices);
-  if (FAILED(hr))
-    return hr;
-
-  if (num_choices == 0) {
-    mswrw::HString description;
-    // TODO(grt): Get a properly translated string.  This can't be done from
-    // within metro_driver.  Consider preprocessing the filter list in Chrome
-    // land to ensure it has this entry if all others are patterns.  In that
-    // case, this whole block of code can be removed.
-    hr = description.Set(L"Data File");
-    if (FAILED(hr))
-      return hr;
-
-    mswr::ComPtr<StringVectorItf> list;
-    hr = mswr::MakeAndInitialize<StringVectorImpl>(
-        list.GetAddressOf(), std::vector<base::string16>(1, L".dat"));
-    if (FAILED(hr))
-      return hr;
-
-    boolean replaced = FALSE;
-    hr = choices->Insert(description.Get(), list.Get(), &replaced);
-    if (FAILED(hr))
-      return hr;
-    DCHECK_EQ(FALSE, replaced);
-  }
-
-  if (!default_path_.empty()) {
-    base::string16 file_part = default_path_.BaseName().value();
-    // If the suggested_name is a root directory, then don't set it as the
-    // suggested name.
-    if (file_part.size() == 1 && file_part[0] == L'\\')
-      file_part.clear();
-    hr = picker->put_SuggestedFileName(
-        mswrw::HStringReference(file_part.c_str()).Get());
-    if (FAILED(hr))
-      return hr;
-  }
-
-  mswr::ComPtr<SaveFileAsyncOp> completion;
-  hr = picker->PickSaveFileAsync(&completion);
-  if (FAILED(hr))
-    return hr;
-
-  // Create the callback method.
-  typedef winfoundtn::IAsyncOperationCompletedHandler<
-      winstorage::StorageFile*> HandlerDoneType;
-  mswr::ComPtr<HandlerDoneType> handler(mswr::Callback<HandlerDoneType>(
-      this, &SaveFilePickerSession::FilePickerDone));
-  DCHECK(handler.Get() != NULL);
-  hr = completion->put_Completed(handler.Get());
-
-  return hr;
-}
-
-HRESULT SaveFilePickerSession::FilePickerDone(SaveFileAsyncOp* async,
-                                              AsyncStatus status) {
-  if (status == Completed) {
-    mswr::ComPtr<winstorage::IStorageFile> file;
-    HRESULT hr = async->GetResults(file.GetAddressOf());
-
-    if (file) {
-      mswr::ComPtr<winstorage::IStorageItem> storage_item;
-      if (SUCCEEDED(hr))
-        hr = file.As(&storage_item);
-
-      mswrw::HString file_path;
-      if (SUCCEEDED(hr))
-        hr = storage_item->get_Path(file_path.GetAddressOf());
-
-      if (SUCCEEDED(hr)) {
-        base::string16 path_str = MakeStdWString(file_path.Get());
-        result_ = path_str;
-        success_ = true;
-      }
-    } else {
-      LOG(ERROR) << "NULL IStorageItem";
-    }
-  } else {
-    LOG(ERROR) << "Unexpected async status " << static_cast<int>(status);
-  }
-  app_view_->OnSaveFileCompleted(this, success_);
-  return S_OK;
-}
-
-FolderPickerSession::FolderPickerSession(ChromeAppViewAsh* app_view,
-                                         const base::string16& title)
-    : FilePickerSessionBase(app_view, title, L"", base::FilePath()) {
-}
-
-HRESULT FolderPickerSession::StartFilePicker() {
-  mswrw::HStringReference class_name(
-      RuntimeClass_Windows_Storage_Pickers_FolderPicker);
-
-  // Create the folder picker.
-  mswr::ComPtr<winstorage::Pickers::IFolderPicker> picker;
-  HRESULT hr = ::Windows::Foundation::ActivateInstance(
-      class_name.Get(), picker.GetAddressOf());
-  CheckHR(hr);
-
-  // Set the file type filter
-  mswr::ComPtr<winfoundtn::Collections::IVector<HSTRING>> filter;
-  hr = picker->get_FileTypeFilter(filter.GetAddressOf());
-  if (FAILED(hr))
-    return hr;
-
-  hr = filter->Append(mswrw::HStringReference(L"*").Get());
-  if (FAILED(hr))
-    return hr;
-
-  mswr::ComPtr<FolderPickerAsyncOp> completion;
-  hr = picker->PickSingleFolderAsync(&completion);
-  if (FAILED(hr))
-    return hr;
-
-  // Create the callback method.
-  typedef winfoundtn::IAsyncOperationCompletedHandler<
-      winstorage::StorageFolder*> HandlerDoneType;
-  mswr::ComPtr<HandlerDoneType> handler(mswr::Callback<HandlerDoneType>(
-      this, &FolderPickerSession::FolderPickerDone));
-  DCHECK(handler.Get() != NULL);
-  hr = completion->put_Completed(handler.Get());
-  return hr;
-}
-
-HRESULT FolderPickerSession::FolderPickerDone(FolderPickerAsyncOp* async,
-                                              AsyncStatus status) {
-  if (status == Completed) {
-    mswr::ComPtr<winstorage::IStorageFolder> folder;
-    HRESULT hr = async->GetResults(folder.GetAddressOf());
-
-    if (folder) {
-      mswr::ComPtr<winstorage::IStorageItem> storage_item;
-      if (SUCCEEDED(hr))
-        hr = folder.As(&storage_item);
-
-      mswrw::HString file_path;
-      if (SUCCEEDED(hr))
-        hr = storage_item->get_Path(file_path.GetAddressOf());
-
-      if (SUCCEEDED(hr)) {
-        base::string16 path_str = MakeStdWString(file_path.Get());
-        result_ = path_str;
-        success_ = true;
-      }
-    } else {
-      LOG(ERROR) << "NULL IStorageItem";
-    }
-  } else {
-    LOG(ERROR) << "Unexpected async status " << static_cast<int>(status);
-  }
-  app_view_->OnFolderPickerCompleted(this, success_);
-  return S_OK;
-}
-
diff --git a/win8/metro_driver/file_picker_ash.h b/win8/metro_driver/file_picker_ash.h
deleted file mode 100644
index 5d41a83..0000000
--- a/win8/metro_driver/file_picker_ash.h
+++ /dev/null
@@ -1,157 +0,0 @@
-// Copyright (c) 2013 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_UI_METRO_DRIVER_FILE_PICKER_ASH_H_
-#define CHROME_BROWSER_UI_METRO_DRIVER_FILE_PICKER_ASH_H_
-
-#include <vector>
-
-#include "base/compiler_specific.h"
-#include "base/files/file_path.h"
-#include "base/macros.h"
-#include "base/strings/string16.h"
-
-class ChromeAppViewAsh;
-struct MetroViewerHostMsg_SaveAsDialogParams;
-
-namespace base {
-class FilePath;
-}
-
-// Base class for the file pickers.
-class FilePickerSessionBase {
- public:
-  virtual ~FilePickerSessionBase();
-
-  // Runs the picker, returns true on success.
-  bool Run();
-
-  const base::string16& result() const { return result_; }
-
-  bool success() const { return success_; }
-
- protected:
-  // Creates a file picker for open_file_name.
-  FilePickerSessionBase(ChromeAppViewAsh* app_view,
-                        const base::string16& title,
-                        const base::string16& filter,
-                        const base::FilePath& default_path);
-
-  // Creates, configures and starts a file picker.
-  // If the HRESULT returned is a failure code the file picker has not started,
-  // so no callbacks should be expected.
-  virtual HRESULT StartFilePicker() = 0;
-
-  // True iff a file picker has successfully finished.
-  bool success_;
-
-  // The title of the file picker.
-  base::string16 title_;
-
-  // The file type filter.
-  base::string16 filter_;
-
-  // The starting directory/file name.
-  base::FilePath default_path_;
-
-  // Pointer to the ChromeAppViewAsh instance. We notify the ChromeAppViewAsh
-  // instance when the file open/save operations complete.
-  ChromeAppViewAsh* app_view_;
-
-  base::string16 result_;
-
- private:
-  // Initiate a file picker, must be called on the main metro thread.
-  // Returns true on success.
-  bool DoFilePicker();
-
-  DISALLOW_COPY_AND_ASSIGN(FilePickerSessionBase);
-};
-
-// Provides functionality to display the open file/multiple open file pickers
-// metro dialog.
-class OpenFilePickerSession : public FilePickerSessionBase {
- public:
-  OpenFilePickerSession(ChromeAppViewAsh* app_view,
-                        const base::string16& title,
-                        const base::string16& filter,
-                        const base::FilePath& default_path,
-                        bool allow_multi_select);
-  ~OpenFilePickerSession() override;
-
-  const std::vector<base::FilePath>& filenames() const {
-    return filenames_;
-  }
-
-  bool allow_multi_select() const { return allow_multi_select_; }
-
- private:
-  HRESULT StartFilePicker() override;
-
-  typedef winfoundtn::IAsyncOperation<winstorage::StorageFile*>
-      SingleFileAsyncOp;
-  typedef winfoundtn::Collections::IVectorView<
-      winstorage::StorageFile*> StorageFileVectorCollection;
-  typedef winfoundtn::IAsyncOperation<StorageFileVectorCollection*>
-      MultiFileAsyncOp;
-
-  // Called asynchronously when a single file picker is done.
-  HRESULT SinglePickerDone(SingleFileAsyncOp* async, AsyncStatus status);
-
-  // Called asynchronously when a multi file picker is done.
-  HRESULT MultiPickerDone(MultiFileAsyncOp* async, AsyncStatus status);
-
-  // Composes a multi-file result string suitable for returning to a
-  // from a storage file collection.
-  static HRESULT ComposeMultiFileResult(StorageFileVectorCollection* files,
-                                        base::string16* result);
-
-  // True if the multi file picker is to be displayed.
-  bool allow_multi_select_;
-  // If multi select is true then this member contains the list of filenames
-  // to be returned back.
-  std::vector<base::FilePath> filenames_;
-
-  DISALLOW_COPY_AND_ASSIGN(OpenFilePickerSession);
-};
-
-// Provides functionality to display the save file picker.
-class SaveFilePickerSession : public FilePickerSessionBase {
- public:
-  SaveFilePickerSession(ChromeAppViewAsh* app_view,
-                        const MetroViewerHostMsg_SaveAsDialogParams& params);
-
-  int filter_index() const;
-
- private:
-  HRESULT StartFilePicker() override;
-
-  typedef winfoundtn::IAsyncOperation<winstorage::StorageFile*> SaveFileAsyncOp;
-
-  // Called asynchronously when the save file picker is done.
-  HRESULT FilePickerDone(SaveFileAsyncOp* async, AsyncStatus status);
-
-  int filter_index_;
-
-  DISALLOW_COPY_AND_ASSIGN(SaveFilePickerSession);
-};
-
-// Provides functionality to display the folder picker.
-class FolderPickerSession : public FilePickerSessionBase {
- public:
-  FolderPickerSession(ChromeAppViewAsh* app_view, const base::string16& title);
-
- private:
-  HRESULT StartFilePicker() override;
-
-  typedef winfoundtn::IAsyncOperation<winstorage::StorageFolder*>
-      FolderPickerAsyncOp;
-
-  // Called asynchronously when the folder picker is done.
-  HRESULT FolderPickerDone(FolderPickerAsyncOp* async, AsyncStatus status);
-
-  DISALLOW_COPY_AND_ASSIGN(FolderPickerSession);
-};
-
-#endif  // CHROME_BROWSER_UI_METRO_DRIVER_FILE_PICKER_ASH_H_
-
diff --git a/win8/metro_driver/metro_driver.cc b/win8/metro_driver/metro_driver.cc
deleted file mode 100644
index 650b238..0000000
--- a/win8/metro_driver/metro_driver.cc
+++ /dev/null
@@ -1,135 +0,0 @@
-// Copyright (c) 2012 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 "stdafx.h"
-#include "win8/metro_driver/metro_driver.h"
-
-#include <roerrorapi.h>
-#include <shobjidl.h>
-
-#include "base/at_exit.h"
-#include "base/command_line.h"
-#include "base/logging.h"
-#include "base/logging_win.h"
-#include "base/win/scoped_comptr.h"
-#include "base/win/windows_version.h"
-#include "win8/metro_driver/winrt_utils.h"
-
-namespace {
-
-#if !defined(NDEBUG)
-LONG WINAPI ErrorReportingHandler(EXCEPTION_POINTERS* ex_info) {
-  // See roerrorapi.h for a description of the
-  // exception codes and parameters.
-  DWORD code = ex_info->ExceptionRecord->ExceptionCode;
-  ULONG_PTR* info = ex_info->ExceptionRecord->ExceptionInformation;
-  if (code == EXCEPTION_RO_ORIGINATEERROR) {
-    base::string16 msg(reinterpret_cast<wchar_t*>(info[2]), info[1]);
-    LOG(ERROR) << "VEH: Metro error 0x" << std::hex << info[0] << ": " << msg;
-  } else if (code == EXCEPTION_RO_TRANSFORMERROR) {
-    base::string16 msg(reinterpret_cast<wchar_t*>(info[3]), info[2]);
-    LOG(ERROR) << "VEH: Metro old error 0x" << std::hex << info[0]
-               << " new error 0x" << info[1] << ": " << msg;
-  }
-
-  return EXCEPTION_CONTINUE_SEARCH;
-}
-#endif
-
-void SetMetroReportingFlags() {
-#if !defined(NDEBUG)
-  // Set the error reporting flags to always raise an exception,
-  // which is then processed by our vectored exception handling
-  // above to log the error message.
-  winfoundtn::Diagnostics::SetErrorReportingFlags(
-      winfoundtn::Diagnostics::UseSetErrorInfo |
-      winfoundtn::Diagnostics::ForceExceptions);
-#endif
-}
-
-// TODO(robertshield): This GUID is hard-coded in a bunch of places that
-//     don't allow explicit includes. Find a single place for it to live.
-// {7FE69228-633E-4f06-80C1-527FEA23E3A7}
-const GUID kChromeTraceProviderName = {
-    0x7fe69228, 0x633e, 0x4f06,
-        { 0x80, 0xc1, 0x52, 0x7f, 0xea, 0x23, 0xe3, 0xa7 } };
-
-}  // namespace
-
-#if !defined(COMPONENT_BUILD)
-// Required for base initialization.
-// TODO(siggi): This should be handled better, as this way our at exit
-//     registrations will run under the loader's lock. However,
-//     once metro_driver is merged into Chrome.dll, this will go away anyhow.
-base::AtExitManager at_exit;
-#endif
-
-mswr::ComPtr<winapp::Core::ICoreApplication> InitWindows8() {
-  SetMetroReportingFlags();
-  HRESULT hr = ::Windows::Foundation::Initialize(RO_INIT_MULTITHREADED);
-  if (FAILED(hr))
-    CHECK(false);
-  mswr::ComPtr<winapp::Core::ICoreApplication> core_app;
-  hr = winrt_utils::CreateActivationFactory(
-      RuntimeClass_Windows_ApplicationModel_Core_CoreApplication,
-      core_app.GetAddressOf());
-  if (FAILED(hr))
-    CHECK(false);
-  return core_app;
-}
-
-mswr::ComPtr<winapp::Core::ICoreApplication> InitWindows7();
-
-extern "C" __declspec(dllexport)
-int InitMetro() {
-  // Metro mode or its emulation is not supported in Vista or XP.
-  if (base::win::GetVersion() < base::win::VERSION_WIN7)
-    return 1;
-  // Initialize the command line.
-  base::CommandLine::Init(0, NULL);
-  // Initialize the logging system.
-  logging::LoggingSettings settings;
-  settings.logging_dest = logging::LOG_TO_SYSTEM_DEBUG_LOG;
-  logging::InitLogging(settings);
-#if defined(NDEBUG)
-  logging::SetMinLogLevel(logging::LOG_ERROR);
-#else
-  logging::SetMinLogLevel(logging::LOG_VERBOSE);
-    HANDLE registration =
-      ::AddVectoredExceptionHandler(TRUE, ErrorReportingHandler);
-#endif
-  // Enable trace control and transport through event tracing for Windows.
-  logging::LogEventProvider::Initialize(kChromeTraceProviderName);
-  DVLOG(1) << "InitMetro";
-
-  // OS specific initialization.
-  mswr::ComPtr<winapp::Core::ICoreApplication> core_app;
-  if (base::win::GetVersion() < base::win::VERSION_WIN8)
-    core_app = InitWindows7();
-  else
-    core_app = InitWindows8();
-
-  auto view_factory = mswr::Make<ChromeAppViewFactory>(core_app.Get());
-  HRESULT hr = core_app->Run(view_factory.Get());
-  DVLOG(1) << "exiting InitMetro, hr=" << hr;
-
-#if !defined(NDEBUG)
-  ::RemoveVectoredExceptionHandler(registration);
-#endif
-  return hr;
-}
-
-// Activates the application known by |app_id|.  Returns, among other things,
-// E_APPLICATION_NOT_REGISTERED if |app_id| identifies Chrome and Chrome is not
-// the default browser.
-extern "C" __declspec(dllexport)
-HRESULT ActivateApplication(const wchar_t* app_id) {
-  base::win::ScopedComPtr<IApplicationActivationManager> activator;
-  HRESULT hr = activator.CreateInstance(CLSID_ApplicationActivationManager);
-  if (SUCCEEDED(hr)) {
-    DWORD pid = 0;
-    hr = activator->ActivateApplication(app_id, L"", AO_NONE, &pid);
-  }
-  return hr;
-}
diff --git a/win8/metro_driver/metro_driver.gyp b/win8/metro_driver/metro_driver.gyp
index caa5ab5..a6f9afa 100644
--- a/win8/metro_driver/metro_driver.gyp
+++ b/win8/metro_driver/metro_driver.gyp
@@ -65,9 +65,6 @@
           'sources': [
             'display_properties.cc',
             'display_properties.h',
-            'metro_driver.cc',
-            'metro_driver.h',
-            'metro_driver_win7.cc',
             'stdafx.h',
             'winrt_utils.cc',
             'winrt_utils.h',
@@ -75,16 +72,9 @@
           ],
           'conditions': [
             ['use_aura==1', {
-              'dependencies': [
-                '../win8.gyp:metro_viewer_constants',
-              ],
               'sources': [
-                'chrome_app_view_ash.cc',
-                'chrome_app_view_ash.h',
                 'direct3d_helper.cc',
                 'direct3d_helper.h',
-                'file_picker_ash.cc',
-                'file_picker_ash.h',
               ],
               'includes': [
                 'ime/ime.gypi',
@@ -97,8 +87,6 @@
                 'chrome_url_launch_handler.h',
                 'devices_handler.cc',
                 'devices_handler.h',
-                'file_picker.cc',
-                'file_picker.h',
                 'metro_dialog_box.cc',
                 'metro_dialog_box.h',
                 'print_document_source.cc',
diff --git a/win8/metro_driver/metro_driver.h b/win8/metro_driver/metro_driver.h
deleted file mode 100644
index da8f1c6..0000000
--- a/win8/metro_driver/metro_driver.h
+++ /dev/null
@@ -1,17 +0,0 @@
-// Copyright (c) 2012 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 WIN8_METRO_DRIVER_METRO_DRIVER_H_
-#define WIN8_METRO_DRIVER_METRO_DRIVER_H_
-
-#include "stdafx.h"
-
-class ChromeAppViewFactory
-    : public mswr::RuntimeClass<winapp::Core::IFrameworkViewSource> {
- public:
-  ChromeAppViewFactory(winapp::Core::ICoreApplication* icore_app);
-  IFACEMETHOD(CreateView)(winapp::Core::IFrameworkView** view) override;
-};
-
-#endif  // WIN8_METRO_DRIVER_METRO_DRIVER_H_
\ No newline at end of file
diff --git a/win8/metro_driver/metro_driver_win7.cc b/win8/metro_driver/metro_driver_win7.cc
deleted file mode 100644
index 62662f5..0000000
--- a/win8/metro_driver/metro_driver_win7.cc
+++ /dev/null
@@ -1,1229 +0,0 @@
-// Copyright (c) 2012 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 "stdafx.h"
-#include <corewindow.h>
-#include <shobjidl.h>
-#include <stdint.h>
-
-#include "base/logging.h"
-#include "base/macros.h"
-#include "ui/gfx/geometry/safe_integer_conversions.h"
-#include "ui/gfx/win/msg_util.h"
-
-#pragma comment(lib, "shell32.lib")
-
-EXTERN_C IMAGE_DOS_HEADER __ImageBase;
-// Even though we only create a single window, we need to keep this
-// count because of the hidden window used by the UI message loop of
-// the metro viewer.
-int g_window_count = 0;
-
-const wchar_t kAshWin7AppId[] = L"Google.Chrome.AshWin7.1";
-const wchar_t kAshWin7CoreWindowHandler[] = L"CoreWindowHandler";
-extern float GetModernUIScale();
-LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wparam,
-                         LPARAM lparam);
-
-HWND CreateMetroTopLevelWindow(const RECT& work_area) {
-  HINSTANCE hInst = reinterpret_cast<HINSTANCE>(&__ImageBase);
-  WNDCLASSEXW wcex;
-  wcex.cbSize = sizeof(wcex);
-  wcex.style              = CS_HREDRAW | CS_VREDRAW;
-  wcex.lpfnWndProc        = WndProc;
-  wcex.cbClsExtra         = 0;
-  wcex.cbWndExtra         = 0;
-  wcex.hInstance          = hInst;
-  wcex.hIcon              = LoadIcon(::GetModuleHandle(NULL), L"IDR_MAINFRAME");
-  wcex.hCursor            = LoadCursor(NULL, IDC_ARROW);
-  wcex.hbrBackground      = (HBRUSH)(COLOR_INACTIVECAPTION+1);
-  wcex.lpszMenuName       = 0;
-  wcex.lpszClassName      = L"Windows.UI.Core.CoreWindow";
-  wcex.hIconSm            = LoadIcon(::GetModuleHandle(NULL), L"IDR_MAINFRAME");
-
-  HWND hwnd = ::CreateWindowExW(0,
-                                MAKEINTATOM(::RegisterClassExW(&wcex)),
-                                L"metro_win7",
-                                WS_POPUP | WS_VISIBLE | WS_MINIMIZEBOX,
-                                work_area.top, work_area.left,
-                                work_area.right, work_area.bottom,
-                                NULL, NULL, hInst, NULL);
-  return hwnd;
-}
-
-typedef winfoundtn::ITypedEventHandler<
-    winapp::Core::CoreApplicationView*,
-    winapp::Activation::IActivatedEventArgs*> ActivatedHandler;
-
-typedef winfoundtn::ITypedEventHandler<
-    winui::Core::CoreWindow*,
-    winui::Core::WindowActivatedEventArgs*> WindowActivatedHandler;
-
-typedef winfoundtn::ITypedEventHandler<
-    winui::Core::CoreWindow*,
-    winui::Core::AutomationProviderRequestedEventArgs*>
-        AutomationProviderHandler;
-
-typedef winfoundtn::ITypedEventHandler<
-    winui::Core::CoreWindow*,
-    winui::Core::CharacterReceivedEventArgs*> CharEventHandler;
-
-typedef winfoundtn::ITypedEventHandler<
-    winui::Core::CoreWindow*,
-    winui::Core::CoreWindowEventArgs*> CoreWindowEventHandler;
-
-typedef winfoundtn::ITypedEventHandler<
-    winui::Core::CoreWindow*,
-    winui::Core::InputEnabledEventArgs*> InputEnabledEventHandler;
-
-typedef winfoundtn::ITypedEventHandler<
-    winui::Core::CoreWindow*,
-    winui::Core::KeyEventArgs*> KeyEventHandler;
-
-typedef winfoundtn::ITypedEventHandler<
-    winui::Core::CoreWindow*,
-    winui::Core::PointerEventArgs*> PointerEventHandler;
-
-typedef winfoundtn::ITypedEventHandler<
-    winui::Core::CoreWindow*,
-    winui::Core::WindowSizeChangedEventArgs*> SizeChangedHandler;
-
-typedef winfoundtn::ITypedEventHandler<
-    winui::Core::CoreWindow*,
-    winui::Core::TouchHitTestingEventArgs*> TouchHitTestHandler;
-
-typedef winfoundtn::ITypedEventHandler<
-    winui::Core::CoreWindow*,
-    winui::Core::VisibilityChangedEventArgs*> VisibilityChangedHandler;
-
-typedef winfoundtn::ITypedEventHandler<
-    winui::Core::CoreDispatcher*,
-    winui::Core::AcceleratorKeyEventArgs*> AcceleratorKeyEventHandler;
-
-// This interface is implemented by classes which handle mouse and keyboard
-// input.
-class InputHandler {
- public:
-  InputHandler() {}
-  virtual ~InputHandler() {}
-
-  virtual bool HandleKeyboardMessage(const MSG& msg) = 0;
-  virtual bool HandleMouseMessage(const MSG& msg) = 0;
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(InputHandler);
-};
-
-// This class implements the winrt interfaces corresponding to mouse input.
-class MouseEvent : public mswr::RuntimeClass<
-    winui::Core::IPointerEventArgs,
-    winui::Input::IPointerPoint,
-    winui::Input::IPointerPointProperties,
-    windevs::Input::IPointerDevice> {
- public:
-  MouseEvent(const MSG& msg)
-      : msg_(msg) {
-  }
-
-  // IPointerEventArgs implementation.
-  HRESULT STDMETHODCALLTYPE
-  get_CurrentPoint(winui::Input::IPointerPoint** point) override {
-    return QueryInterface(winui::Input::IID_IPointerPoint,
-                          reinterpret_cast<void**>(point));
-  }
-
-  HRESULT STDMETHODCALLTYPE
-  get_KeyModifiers(winsys::VirtualKeyModifiers* modifiers) override {
-    return E_NOTIMPL;
-  }
-
-  HRESULT STDMETHODCALLTYPE GetIntermediatePoints(
-      winfoundtn::Collections::IVector<winui::Input::PointerPoint*>** points)
-      override {
-    return E_NOTIMPL;
-  }
-
-  // IPointerPoint implementation.
-  HRESULT STDMETHODCALLTYPE
-  get_PointerDevice(windevs::Input::IPointerDevice** pointer_device) override {
-    return QueryInterface(windevs::Input::IID_IPointerDevice,
-                          reinterpret_cast<void**>(pointer_device));
-  }
-
-  HRESULT STDMETHODCALLTYPE get_Position(winfoundtn::Point* position) override {
-    static float scale = GetModernUIScale();
-    // Scale down the points here as they are scaled up on the other side.
-    position->X = gfx::ToRoundedInt(CR_GET_X_LPARAM(msg_.lParam) / scale);
-    position->Y = gfx::ToRoundedInt(CR_GET_Y_LPARAM(msg_.lParam) / scale);
-    return S_OK;
-  }
-
-  HRESULT STDMETHODCALLTYPE get_PointerId(uint32_t* pointer_id) override {
-    // TODO(ananta)
-    // Implement this properly.
-    *pointer_id = 1;
-    return S_OK;
-  }
-
-  HRESULT STDMETHODCALLTYPE get_Timestamp(uint64_t* timestamp) override {
-    *timestamp = msg_.time;
-    return S_OK;
-  }
-
-  HRESULT STDMETHODCALLTYPE
-  get_Properties(winui::Input::IPointerPointProperties** properties) override {
-    return QueryInterface(winui::Input::IID_IPointerPointProperties,
-                          reinterpret_cast<void**>(properties));
-  }
-
-  HRESULT STDMETHODCALLTYPE
-  get_RawPosition(winfoundtn::Point* position) override {
-    return E_NOTIMPL;
-  }
-
-  HRESULT STDMETHODCALLTYPE get_FrameId(uint32_t* frame_id) override {
-    return E_NOTIMPL;
-  }
-
-  HRESULT STDMETHODCALLTYPE get_IsInContact(boolean* in_contact) override {
-    return E_NOTIMPL;
-  }
-
-  // IPointerPointProperties implementation.
-  HRESULT STDMETHODCALLTYPE
-  get_PointerUpdateKind(winui::Input::PointerUpdateKind* update_kind) override {
-    // TODO(ananta)
-    // There is no WM_POINTERUPDATE equivalent on Windows 7. Look into
-    // equivalents.
-    if (msg_.message == WM_LBUTTONDOWN) {
-      *update_kind = winui::Input::PointerUpdateKind_LeftButtonPressed;
-    } else if (msg_.message == WM_RBUTTONDOWN) {
-      *update_kind = winui::Input::PointerUpdateKind_RightButtonPressed;
-    } else if (msg_.message == WM_MBUTTONDOWN) {
-      *update_kind = winui::Input::PointerUpdateKind_MiddleButtonPressed;
-    } else if (msg_.message == WM_LBUTTONUP) {
-      *update_kind = winui::Input::PointerUpdateKind_LeftButtonReleased;
-    } else if (msg_.message == WM_RBUTTONUP) {
-      *update_kind = winui::Input::PointerUpdateKind_RightButtonReleased;
-    } else if (msg_.message == WM_MBUTTONUP) {
-      *update_kind = winui::Input::PointerUpdateKind_MiddleButtonReleased;
-    }
-    return S_OK;
-  }
-
-  HRESULT STDMETHODCALLTYPE
-  get_IsLeftButtonPressed(boolean* left_button_pressed) override {
-    *left_button_pressed = msg_.wParam & MK_LBUTTON ? true : false;
-    return S_OK;
-  }
-
-  HRESULT STDMETHODCALLTYPE
-  get_IsRightButtonPressed(boolean* right_button_pressed) override {
-    *right_button_pressed = msg_.wParam & MK_RBUTTON ? true : false;
-    return S_OK;
-  }
-
-  HRESULT STDMETHODCALLTYPE
-  get_IsMiddleButtonPressed(boolean* middle_button_pressed) override {
-    *middle_button_pressed = msg_.wParam & MK_MBUTTON ? true : false;
-    return S_OK;
-  }
-
-  HRESULT STDMETHODCALLTYPE
-  get_IsHorizontalMouseWheel(boolean* is_horizontal_mouse_wheel) override {
-    *is_horizontal_mouse_wheel =
-        (msg_.message == WM_MOUSEHWHEEL) ? true : false;
-    return S_OK;
-  }
-
-  HRESULT STDMETHODCALLTYPE get_MouseWheelDelta(int* delta) override {
-    if (msg_.message == WM_MOUSEWHEEL || msg_.message == WM_MOUSEHWHEEL) {
-      *delta = GET_WHEEL_DELTA_WPARAM(msg_.wParam);
-      return S_OK;
-    } else {
-      return S_FALSE;
-    }
-  }
-
-  HRESULT STDMETHODCALLTYPE get_Pressure(float* pressure) override {
-    return E_NOTIMPL;
-  }
-
-  HRESULT STDMETHODCALLTYPE get_IsInverted(boolean* inverted) override {
-    return E_NOTIMPL;
-  }
-
-  HRESULT STDMETHODCALLTYPE get_IsEraser(boolean* is_eraser) override {
-    return E_NOTIMPL;
-  }
-
-  HRESULT STDMETHODCALLTYPE get_Orientation(float* orientation) override {
-    return E_NOTIMPL;
-  }
-
-  HRESULT STDMETHODCALLTYPE get_XTilt(float* x_tilt) override {
-    return E_NOTIMPL;
-  }
-
-  HRESULT STDMETHODCALLTYPE get_YTilt(float* y_tilt) override {
-    return E_NOTIMPL;
-  }
-
-  HRESULT STDMETHODCALLTYPE get_Twist(float* twist) override {
-    return E_NOTIMPL;
-  }
-
-  HRESULT STDMETHODCALLTYPE get_ContactRect(winfoundtn::Rect* rect) override {
-    return E_NOTIMPL;
-  }
-
-  HRESULT STDMETHODCALLTYPE
-  get_ContactRectRaw(winfoundtn::Rect* rect) override {
-    return E_NOTIMPL;
-  }
-
-  HRESULT STDMETHODCALLTYPE get_TouchConfidence(boolean* confidence) override {
-    return E_NOTIMPL;
-  }
-
-  HRESULT STDMETHODCALLTYPE get_IsPrimary(boolean* is_primary) override {
-    return E_NOTIMPL;
-  }
-
-  HRESULT STDMETHODCALLTYPE get_IsInRange(boolean* is_in_range) override {
-    return E_NOTIMPL;
-  }
-
-  HRESULT STDMETHODCALLTYPE get_IsCanceled(boolean* is_canceled) override {
-    return E_NOTIMPL;
-  }
-
-  HRESULT STDMETHODCALLTYPE
-  get_IsBarrelButtonPressed(boolean* is_barrel_button_pressed) override {
-    return E_NOTIMPL;
-  }
-
-  HRESULT STDMETHODCALLTYPE
-  get_IsXButton1Pressed(boolean* is_xbutton1_pressed) override {
-    return E_NOTIMPL;
-  }
-
-  HRESULT STDMETHODCALLTYPE
-  get_IsXButton2Pressed(boolean* is_xbutton2_pressed) override {
-    return E_NOTIMPL;
-  }
-
-  HRESULT STDMETHODCALLTYPE HasUsage(uint32_t usage_page,
-                                     uint32_t usage_id,
-                                     boolean* has_usage) override {
-    return E_NOTIMPL;
-  }
-
-  HRESULT STDMETHODCALLTYPE GetUsageValue(uint32_t usage_page,
-                                          uint32_t usage_id,
-                                          int32_t* usage_value) override {
-    return E_NOTIMPL;
-  }
-
-  // IPointerDevice implementation.
-  HRESULT STDMETHODCALLTYPE get_PointerDeviceType(
-      windevs::Input::PointerDeviceType* device_type) override {
-    if (msg_.message == WM_TOUCH) {
-      *device_type = windevs::Input::PointerDeviceType_Touch;
-    } else {
-      *device_type = windevs::Input::PointerDeviceType_Mouse;
-    }
-    return S_OK;
-  }
-
-  HRESULT STDMETHODCALLTYPE get_IsIntegrated(boolean* is_integrated) override {
-    return E_NOTIMPL;
-  }
-
-  HRESULT STDMETHODCALLTYPE get_MaxContacts(uint32_t* contacts) override {
-    return E_NOTIMPL;
-  }
-
-  HRESULT STDMETHODCALLTYPE
-  get_PhysicalDeviceRect(winfoundtn::Rect* rect) override {
-    return E_NOTIMPL;
-  }
-
-  HRESULT STDMETHODCALLTYPE get_ScreenRect(winfoundtn::Rect* rect) override {
-    return E_NOTIMPL;
-  }
-
-  HRESULT STDMETHODCALLTYPE get_SupportedUsages(
-      winfoundtn::Collections::IVectorView<windevs::Input::PointerDeviceUsage>**
-          usages) override {
-    return E_NOTIMPL;
-  }
-
- private:
-  MSG msg_;
-
-  DISALLOW_COPY_AND_ASSIGN(MouseEvent);
-};
-
-// This class implements the winrt interfaces needed to support keyboard
-// character and system character messages.
-class KeyEvent : public mswr::RuntimeClass<
-    winui::Core::IKeyEventArgs,
-    winui::Core::ICharacterReceivedEventArgs,
-    winui::Core::IAcceleratorKeyEventArgs> {
- public:
-  KeyEvent(const MSG& msg)
-      : msg_(msg) {}
-
-  // IKeyEventArgs implementation.
-  HRESULT STDMETHODCALLTYPE
-  get_VirtualKey(winsys::VirtualKey* virtual_key) override {
-    *virtual_key = static_cast<winsys::VirtualKey>(msg_.wParam);
-    return S_OK;
-  }
-
-  HRESULT STDMETHODCALLTYPE
-  get_KeyStatus(winui::Core::CorePhysicalKeyStatus* key_status) override {
-    // As per msdn documentation for the keyboard messages.
-    key_status->RepeatCount = msg_.lParam & 0x0000FFFF;
-    key_status->ScanCode = (msg_.lParam >> 16) & 0x00FF;
-    key_status->IsExtendedKey = (msg_.lParam & (1 << 24));
-    key_status->IsMenuKeyDown = (msg_.lParam & (1 << 29));
-    key_status->WasKeyDown = (msg_.lParam & (1 << 30));
-    key_status->IsKeyReleased = (msg_.lParam & (1 << 31));
-    return S_OK;
-  }
-
-  // ICharacterReceivedEventArgs implementation.
-  HRESULT STDMETHODCALLTYPE get_KeyCode(uint32_t* key_code) override {
-    *key_code = msg_.wParam;
-    return S_OK;
-  }
-
-  // IAcceleratorKeyEventArgs implementation.
-  HRESULT STDMETHODCALLTYPE
-  get_EventType(winui::Core::CoreAcceleratorKeyEventType* event_type) override {
-    if (msg_.message == WM_SYSKEYDOWN) {
-      *event_type = winui::Core::CoreAcceleratorKeyEventType_SystemKeyDown;
-    } else if (msg_.message == WM_SYSKEYUP) {
-      *event_type = winui::Core::CoreAcceleratorKeyEventType_SystemKeyUp;
-    } else if (msg_.message == WM_SYSCHAR) {
-      *event_type = winui::Core::CoreAcceleratorKeyEventType_SystemCharacter;
-    }
-    return S_OK;
-  }
-
- private:
-  MSG msg_;
-};
-
-// The following classes are the emulation of the WinRT system as exposed
-// to metro applications. There is one application (ICoreApplication) which
-// contains a series of Views (ICoreApplicationView) each one of them
-// containing a CoreWindow which represents a surface that can drawn to
-// and that receives events.
-//
-// Here is the general dependency hierachy in terms of interfaces:
-//
-//  IFrameworkViewSource --> IFrameworkView
-//          ^                     |
-//          |                     |                          metro app
-//  ---------------------------------------------------------------------
-//          |                     |                         winRT system
-//          |                     v
-//  ICoreApplication     ICoreApplicationView
-//                                |
-//                                v
-//                          ICoreWindow -----> ICoreWindowInterop
-//                                |                  |
-//                                |                  |
-//                                v                  V
-//                         ICoreDispatcher  <==>  real HWND
-//
-class CoreDispatcherEmulation :
-    public mswr::RuntimeClass<
-        winui::Core::ICoreDispatcher,
-        winui::Core::ICoreAcceleratorKeys> {
- public:
-  CoreDispatcherEmulation(InputHandler* input_handler)
-      : input_handler_(input_handler),
-        accelerator_key_event_handler_(NULL) {}
-
-  // ICoreDispatcher implementation:
-  HRESULT STDMETHODCALLTYPE get_HasThreadAccess(boolean* value) override {
-    return S_OK;
-  }
-
-  HRESULT STDMETHODCALLTYPE
-  ProcessEvents(winui::Core::CoreProcessEventsOption options) override {
-    // We don't support the other message pump modes. So we basically enter a
-    // traditional message loop that we only exit a teardown.
-    if (options != winui::Core::CoreProcessEventsOption_ProcessUntilQuit)
-      return E_FAIL;
-
-    MSG msg = {0};
-    while((::GetMessage(&msg, NULL, 0, 0) != 0) && g_window_count > 0) {
-      ProcessInputMessage(msg);
-      ::TranslateMessage(&msg);
-      ::DispatchMessage(&msg);
-    }
-    // TODO(cpu): figure what to do with msg.WParam which we would normally
-    // return here.
-    return S_OK;
-  }
-
-  HRESULT STDMETHODCALLTYPE
-  RunAsync(winui::Core::CoreDispatcherPriority priority,
-           winui::Core::IDispatchedHandler* agileCallback,
-           ABI::Windows::Foundation::IAsyncAction** asyncAction) override {
-    return S_OK;
-  }
-
-  HRESULT STDMETHODCALLTYPE
-  RunIdleAsync(winui::Core::IIdleDispatchedHandler* agileCallback,
-               winfoundtn::IAsyncAction** asyncAction) override {
-    return S_OK;
-  }
-
-  // ICoreAcceleratorKeys implementation:
-  HRESULT STDMETHODCALLTYPE
-  add_AcceleratorKeyActivated(AcceleratorKeyEventHandler* handler,
-                              EventRegistrationToken* pCookie) override {
-    accelerator_key_event_handler_ = handler;
-    accelerator_key_event_handler_->AddRef();
-    return S_OK;
-  }
-
-  HRESULT STDMETHODCALLTYPE
-  remove_AcceleratorKeyActivated(EventRegistrationToken cookie) override {
-    accelerator_key_event_handler_->Release();
-    accelerator_key_event_handler_ = NULL;
-    return S_OK;
-  }
-
- private:
-  bool ProcessInputMessage(const MSG& msg) {
-    // Poor man's way of dispatching input events.
-    bool ret = false;
-    if (input_handler_) {
-      if ((msg.message >= WM_KEYFIRST) && (msg.message <= WM_KEYLAST)) {
-        if ((msg.message == WM_SYSKEYDOWN) || (msg.message == WM_SYSKEYUP) ||
-            msg.message == WM_SYSCHAR) {
-          ret = HandleSystemKeys(msg);
-        } else {
-          ret = input_handler_->HandleKeyboardMessage(msg);
-        }
-      } else if ((msg.message >= WM_MOUSEFIRST) &&
-                  (msg.message <= WM_MOUSELAST)) {
-        ret = input_handler_->HandleMouseMessage(msg);
-      }
-    }
-    return ret;
-  }
-
-  bool HandleSystemKeys(const MSG& msg) {
-    mswr::ComPtr<winui::Core::IAcceleratorKeyEventArgs> event_args;
-    event_args = mswr::Make<KeyEvent>(msg);
-    accelerator_key_event_handler_->Invoke(this, event_args.Get());
-    return true;
-  }
-
-  InputHandler* input_handler_;
-  AcceleratorKeyEventHandler* accelerator_key_event_handler_;
-};
-
-class CoreWindowEmulation
-    : public mswr::RuntimeClass<
-        mswr::RuntimeClassFlags<mswr::WinRtClassicComMix>,
-        winui::Core::ICoreWindow, ICoreWindowInterop>,
-      public InputHandler {
- public:
-  CoreWindowEmulation(winapp::Core::IFrameworkView* app_view)
-      : mouse_moved_handler_(NULL),
-        mouse_capture_lost_handler_(NULL),
-        mouse_pressed_handler_(NULL),
-        mouse_released_handler_(NULL),
-        mouse_entered_handler_(NULL),
-        mouse_exited_handler_(NULL),
-        mouse_wheel_changed_handler_(NULL),
-        key_down_handler_(NULL),
-        key_up_handler_(NULL),
-        character_received_handler_(NULL),
-        core_hwnd_(NULL),
-        app_view_(app_view),
-        window_activated_handler_(NULL) {
-    dispatcher_ = mswr::Make<CoreDispatcherEmulation>(this);
-
-    // Unless we select our own AppUserModelID the shell might confuse us
-    // with the app launcher one and we get the wrong taskbar button and icon.
-    ::SetCurrentProcessExplicitAppUserModelID(kAshWin7AppId);
-
-    RECT work_area = {0};
-    ::SystemParametersInfo(SPI_GETWORKAREA, 0, &work_area, 0);
-    if (::IsDebuggerPresent()) {
-      work_area.top = 0;
-      work_area.left = 0;
-      work_area.right = 1600;
-      work_area.bottom = 900;
-    }
-
-    core_hwnd_ = CreateMetroTopLevelWindow(work_area);
-    ::SetProp(core_hwnd_, kAshWin7CoreWindowHandler, this);
-  }
-
-  ~CoreWindowEmulation() override {
-    if (core_hwnd_) {
-      ::RemoveProp(core_hwnd_, kAshWin7CoreWindowHandler);
-      ::DestroyWindow(core_hwnd_);
-    }
-  }
-
-  // ICoreWindow implementation:
-  HRESULT STDMETHODCALLTYPE
-  get_AutomationHostProvider(IInspectable** value) override {
-    return S_OK;
-  }
-
-  HRESULT STDMETHODCALLTYPE get_Bounds(winfoundtn::Rect* value) override {
-    RECT rect;
-    if (!::GetClientRect(core_hwnd_, &rect))
-      return E_FAIL;
-    value->Width = rect.right;
-    value->Height = rect.bottom;
-    return S_OK;
-  }
-
-  HRESULT STDMETHODCALLTYPE
-  get_CustomProperties(winfoundtn::Collections::IPropertySet** value) override {
-    return S_OK;
-  }
-
-  HRESULT STDMETHODCALLTYPE
-  get_Dispatcher(winui::Core::ICoreDispatcher** value) override {
-    return dispatcher_.CopyTo(value);
-  }
-
-  HRESULT STDMETHODCALLTYPE
-  get_FlowDirection(winui::Core::CoreWindowFlowDirection* value) override {
-    return S_OK;
-  }
-
-  HRESULT STDMETHODCALLTYPE
-  put_FlowDirection(winui::Core::CoreWindowFlowDirection value) override {
-    return S_OK;
-  }
-
-  HRESULT STDMETHODCALLTYPE get_IsInputEnabled(boolean* value) override {
-    return S_OK;
-  }
-
-  HRESULT STDMETHODCALLTYPE put_IsInputEnabled(boolean value) override {
-    return S_OK;
-  }
-
-  HRESULT STDMETHODCALLTYPE
-  get_PointerCursor(winui::Core::ICoreCursor** value) override {
-    return S_OK;
-  }
-
-  HRESULT STDMETHODCALLTYPE
-  put_PointerCursor(winui::Core::ICoreCursor* value) override {
-    return S_OK;
-  }
-
-  HRESULT STDMETHODCALLTYPE
-  get_PointerPosition(winfoundtn::Point* value) override {
-    return S_OK;
-  }
-
-  HRESULT STDMETHODCALLTYPE get_Visible(boolean* value) override {
-    return S_OK;
-  }
-
-  HRESULT STDMETHODCALLTYPE Activate(void) override {
-    // After we fire OnActivate on the View, Chrome calls us back here.
-    return S_OK;
-  }
-
-  HRESULT STDMETHODCALLTYPE Close(void) override {
-    ::PostMessage(core_hwnd_, WM_CLOSE, 0, 0);
-    core_hwnd_ = NULL;
-    return S_OK;
-  }
-
-  HRESULT STDMETHODCALLTYPE GetAsyncKeyState(
-      ABI::Windows::System::VirtualKey virtualKey,
-      winui::Core::CoreVirtualKeyStates* KeyState) override {
-    return S_OK;
-  }
-
-  HRESULT STDMETHODCALLTYPE GetKeyState(
-      ABI::Windows::System::VirtualKey virtualKey,
-      winui::Core::CoreVirtualKeyStates* KeyState) override {
-    return S_OK;
-  }
-
-  HRESULT STDMETHODCALLTYPE ReleasePointerCapture(void) override {
-    return S_OK;
-  }
-
-  HRESULT STDMETHODCALLTYPE SetPointerCapture(void) override {
-    return S_OK;
-  }
-
-  HRESULT STDMETHODCALLTYPE add_Activated(
-      WindowActivatedHandler* handler,
-      EventRegistrationToken* pCookie) override {
-    window_activated_handler_ = handler;
-    handler->AddRef();
-    return S_OK;
-  }
-
-  HRESULT STDMETHODCALLTYPE remove_Activated(
-      EventRegistrationToken cookie) override {
-    window_activated_handler_->Release();
-    window_activated_handler_ = NULL;
-    return S_OK;
-  }
-
-  HRESULT STDMETHODCALLTYPE add_AutomationProviderRequested(
-      AutomationProviderHandler* handler,
-      EventRegistrationToken* cookie) override {
-    return S_OK;
-  }
-
-  HRESULT STDMETHODCALLTYPE remove_AutomationProviderRequested(
-      EventRegistrationToken cookie) override {
-    return S_OK;
-  }
-
-  HRESULT STDMETHODCALLTYPE add_CharacterReceived(
-      CharEventHandler* handler,
-      EventRegistrationToken* pCookie) override {
-    character_received_handler_ = handler;
-    character_received_handler_->AddRef();
-    return S_OK;
-  }
-
-  HRESULT STDMETHODCALLTYPE remove_CharacterReceived(
-      EventRegistrationToken cookie) override {
-    character_received_handler_->Release();
-    character_received_handler_ = NULL;
-    return S_OK;
-  }
-
-  HRESULT STDMETHODCALLTYPE add_Closed(
-      CoreWindowEventHandler* handler,
-      EventRegistrationToken* pCookie) override {
-    return S_OK;
-  }
-
-  HRESULT STDMETHODCALLTYPE remove_Closed(
-      EventRegistrationToken cookie) override {
-    return S_OK;
-  }
-
-  HRESULT STDMETHODCALLTYPE add_InputEnabled(
-      InputEnabledEventHandler* handler,
-      EventRegistrationToken* pCookie) override {
-    return S_OK;
-  }
-
-  HRESULT STDMETHODCALLTYPE remove_InputEnabled(
-      EventRegistrationToken cookie) override {
-    return S_OK;
-  }
-
-  HRESULT STDMETHODCALLTYPE add_KeyDown(
-      KeyEventHandler* handler,
-      EventRegistrationToken* pCookie) override {
-    key_down_handler_ = handler;
-    key_down_handler_->AddRef();
-    return S_OK;
-  }
-
-  HRESULT STDMETHODCALLTYPE remove_KeyDown(
-      EventRegistrationToken cookie) override {
-    key_down_handler_->Release();
-    key_down_handler_ = NULL;
-    return S_OK;
-  }
-
-  HRESULT STDMETHODCALLTYPE add_KeyUp(
-      KeyEventHandler* handler,
-      EventRegistrationToken* pCookie) override {
-    key_up_handler_ = handler;
-    key_up_handler_->AddRef();
-    return S_OK;
-  }
-
-  HRESULT STDMETHODCALLTYPE remove_KeyUp(
-      EventRegistrationToken cookie) override {
-    key_up_handler_->Release();
-    key_up_handler_ = NULL;
-    return S_OK;
-  }
-
-  HRESULT STDMETHODCALLTYPE add_PointerCaptureLost(
-      PointerEventHandler* handler,
-      EventRegistrationToken* cookie) override {
-    mouse_capture_lost_handler_ = handler;
-    return S_OK;
-  }
-
-  HRESULT STDMETHODCALLTYPE remove_PointerCaptureLost(
-      EventRegistrationToken cookie) override {
-    mouse_capture_lost_handler_ = NULL;
-    return S_OK;
-  }
-
-  HRESULT STDMETHODCALLTYPE add_PointerEntered(
-      PointerEventHandler* handler,
-      EventRegistrationToken* cookie) override {
-    mouse_entered_handler_ = handler;
-    return S_OK;
-  }
-
-  HRESULT STDMETHODCALLTYPE remove_PointerEntered(
-      EventRegistrationToken cookie) override {
-    mouse_entered_handler_ = NULL;
-    return S_OK;
-  }
-
-  HRESULT STDMETHODCALLTYPE add_PointerExited(
-      PointerEventHandler* handler,
-      EventRegistrationToken* cookie) override {
-    mouse_exited_handler_ = handler;
-    return S_OK;
-  }
-
-  HRESULT STDMETHODCALLTYPE remove_PointerExited(
-      EventRegistrationToken cookie) override {
-    mouse_exited_handler_ = NULL;
-    return S_OK;
-  }
-
-  HRESULT STDMETHODCALLTYPE add_PointerMoved(
-      PointerEventHandler* handler,
-      EventRegistrationToken* cookie) override {
-    mouse_moved_handler_ = handler;
-    mouse_moved_handler_->AddRef();
-    return S_OK;
-  }
-
-  HRESULT STDMETHODCALLTYPE remove_PointerMoved(
-      EventRegistrationToken cookie) override {
-    mouse_moved_handler_->Release();
-    mouse_moved_handler_ = NULL;
-    return S_OK;
-  }
-
-  HRESULT STDMETHODCALLTYPE add_PointerPressed(
-      PointerEventHandler* handler,
-      EventRegistrationToken* cookie) override {
-    mouse_pressed_handler_ = handler;
-    mouse_pressed_handler_->AddRef();
-    return S_OK;
-  }
-
-  HRESULT STDMETHODCALLTYPE remove_PointerPressed(
-      EventRegistrationToken cookie) override {
-    mouse_pressed_handler_->Release();
-    mouse_pressed_handler_ = NULL;
-    return S_OK;
-  }
-
-  HRESULT STDMETHODCALLTYPE add_PointerReleased(
-      PointerEventHandler* handler,
-      EventRegistrationToken* cookie) override {
-    mouse_released_handler_ = handler;
-    mouse_released_handler_->AddRef();
-    return S_OK;
-  }
-
-  HRESULT STDMETHODCALLTYPE remove_PointerReleased(
-      EventRegistrationToken cookie) override {
-    mouse_released_handler_->Release();
-    mouse_released_handler_ = NULL;
-    return S_OK;
-  }
-
-  HRESULT STDMETHODCALLTYPE add_TouchHitTesting(
-      TouchHitTestHandler* handler,
-      EventRegistrationToken* pCookie) override {
-    return S_OK;
-  }
-
-  HRESULT STDMETHODCALLTYPE remove_TouchHitTesting(
-      EventRegistrationToken cookie) override {
-    return S_OK;
-  }
-
-  HRESULT STDMETHODCALLTYPE add_PointerWheelChanged(
-      PointerEventHandler* handler,
-      EventRegistrationToken* cookie) override {
-    mouse_wheel_changed_handler_ = handler;
-    mouse_wheel_changed_handler_->AddRef();
-    return S_OK;
-  }
-
-  HRESULT STDMETHODCALLTYPE remove_PointerWheelChanged(
-      EventRegistrationToken cookie) override {
-    mouse_wheel_changed_handler_->Release();
-    mouse_wheel_changed_handler_ = NULL;
-    return S_OK;
-  }
-
-  HRESULT STDMETHODCALLTYPE add_SizeChanged(
-      SizeChangedHandler* handler,
-      EventRegistrationToken* pCookie) override {
-    // TODO(cpu): implement this.
-    return S_OK;
-  }
-
-  HRESULT STDMETHODCALLTYPE remove_SizeChanged(
-      EventRegistrationToken cookie) override {
-    return S_OK;
-  }
-
-  HRESULT STDMETHODCALLTYPE add_VisibilityChanged(
-      VisibilityChangedHandler* handler,
-      EventRegistrationToken* pCookie) override {
-    return S_OK;
-  }
-
-  HRESULT STDMETHODCALLTYPE remove_VisibilityChanged(
-      EventRegistrationToken cookie) override {
-    return S_OK;
-  }
-
-  // ICoreWindowInterop implementation:
-  HRESULT STDMETHODCALLTYPE get_WindowHandle(HWND* hwnd) override {
-    if (!core_hwnd_)
-      return E_FAIL;
-    *hwnd = core_hwnd_;
-    return S_OK;
-  }
-
-  HRESULT STDMETHODCALLTYPE put_MessageHandled(boolean value) override {
-    return S_OK;
-  }
-
-  // InputHandler
-  bool HandleKeyboardMessage(const MSG& msg) override {
-    switch (msg.message) {
-      case WM_KEYDOWN:
-      case WM_KEYUP: {
-        mswr::ComPtr<winui::Core::IKeyEventArgs> event_args;
-        event_args = mswr::Make<KeyEvent>(msg);
-        KeyEventHandler* handler = NULL;
-        if (msg.message == WM_KEYDOWN) {
-          handler = key_down_handler_;
-        } else {
-          handler = key_up_handler_;
-        }
-        handler->Invoke(this, event_args.Get());
-        break;
-      }
-
-      case WM_CHAR:
-      case WM_DEADCHAR:
-      case WM_UNICHAR: {
-        mswr::ComPtr<winui::Core::ICharacterReceivedEventArgs> event_args;
-        event_args = mswr::Make<KeyEvent>(msg);
-        character_received_handler_->Invoke(this, event_args.Get());
-        break;
-      }
-
-      default:
-        return false;
-    }
-    return true;
-  }
-
-  bool HandleMouseMessage(const MSG& msg) override {
-    PointerEventHandler* handler = NULL;
-    mswr::ComPtr<winui::Core::IPointerEventArgs> event_args;
-    event_args = mswr::Make<MouseEvent>(msg);
-    switch (msg.message) {
-      case WM_MOUSEMOVE: {
-        handler = mouse_moved_handler_;
-        break;
-      }
-      case WM_LBUTTONDOWN: {
-      case WM_RBUTTONDOWN:
-      case WM_MBUTTONDOWN:
-        handler = mouse_pressed_handler_;
-        break;
-      }
-
-      case WM_LBUTTONUP: {
-      case WM_RBUTTONUP:
-      case WM_MBUTTONUP:
-        handler = mouse_released_handler_;
-        break;
-      }
-
-      case WM_MOUSEWHEEL: {
-      case WM_MOUSEHWHEEL:
-        handler = mouse_wheel_changed_handler_;
-        break;
-      }
-
-      default:
-        return false;
-    }
-    DCHECK(handler);
-    handler->Invoke(this, event_args.Get());
-    return true;
-  }
-
-  void OnWindowActivated() {
-    if (window_activated_handler_)
-      window_activated_handler_->Invoke(this, NULL);
-  }
-
- private:
-   PointerEventHandler* mouse_moved_handler_;
-   PointerEventHandler* mouse_capture_lost_handler_;
-   PointerEventHandler* mouse_pressed_handler_;
-   PointerEventHandler* mouse_released_handler_;
-   PointerEventHandler* mouse_entered_handler_;
-   PointerEventHandler* mouse_exited_handler_;
-   PointerEventHandler* mouse_wheel_changed_handler_;
-   KeyEventHandler* key_down_handler_;
-   KeyEventHandler* key_up_handler_;
-   CharEventHandler* character_received_handler_;
-   HWND core_hwnd_;
-   mswr::ComPtr<winui::Core::ICoreDispatcher> dispatcher_;
-   mswr::ComPtr<winapp::Core::IFrameworkView> app_view_;
-   WindowActivatedHandler* window_activated_handler_;
-};
-
-LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
-                         WPARAM wparam, LPARAM lparam) {
-  PAINTSTRUCT ps;
-  HDC hdc;
-  switch (message) {
-    case WM_ACTIVATE: {
-      // HIWORD(wparam) is 1 if the window is minimized.
-      bool active = (LOWORD(wparam) != WA_INACTIVE) && !HIWORD(wparam);
-      if (active) {
-        CoreWindowEmulation* core_window_handler =
-            reinterpret_cast<CoreWindowEmulation*>(
-                ::GetProp(hwnd, kAshWin7CoreWindowHandler));
-        if (core_window_handler)
-          core_window_handler->OnWindowActivated();
-      }
-      return ::DefWindowProc(hwnd, message, wparam, lparam);
-    }
-    case WM_CREATE:
-      ++g_window_count;
-      break;
-    case WM_PAINT:
-      hdc = ::BeginPaint(hwnd, &ps);
-      ::EndPaint(hwnd, &ps);
-      break;
-    case WM_CLOSE:
-      ::DestroyWindow(hwnd);
-      break;
-    case WM_DESTROY:
-      --g_window_count;
-      if (!g_window_count)
-        ::PostQuitMessage(0);
-      break;
-    // Always allow Chrome to set the cursor.
-    case WM_SETCURSOR:
-      return 1;
-    default:
-      return ::DefWindowProc(hwnd, message, wparam, lparam);
-  }
-  return 0;
-}
-
-class ActivatedEvent
-    : public mswr::RuntimeClass<winapp::Activation::IActivatedEventArgs> {
- public:
-  ActivatedEvent(winapp::Activation::ActivationKind activation_kind)
-    : activation_kind_(activation_kind) {
-  }
-
-  HRESULT STDMETHODCALLTYPE
-  get_Kind(winapp::Activation::ActivationKind* value) override {
-    *value = activation_kind_;
-    return S_OK;
-  }
-
-  HRESULT STDMETHODCALLTYPE get_PreviousExecutionState(
-      winapp::Activation::ApplicationExecutionState* value) override {
-    *value = winapp::Activation::ApplicationExecutionState_ClosedByUser;
-    return S_OK;
-  }
-
-  HRESULT STDMETHODCALLTYPE
-  get_SplashScreen(winapp::Activation::ISplashScreen** value) override {
-    return E_FAIL;
-  }
-
- private:
-  winapp::Activation::ActivationKind activation_kind_;
-};
-
-class CoreApplicationViewEmulation
-    : public mswr::RuntimeClass<winapp::Core::ICoreApplicationView> {
- public:
-   CoreApplicationViewEmulation(winapp::Core::IFrameworkView* app_view) {
-      core_window_ = mswr::Make<CoreWindowEmulation>(app_view);
-   }
-
-  HRESULT Activate() {
-    if (activated_handler_) {
-      auto ae = mswr::Make<ActivatedEvent>(
-        winapp::Activation::ActivationKind_File);
-      return activated_handler_->Invoke(this, ae.Get());
-    } else {
-      return S_OK;
-    }
-  }
-
-  HRESULT Close() {
-    return core_window_->Close();
-  }
-
-  // ICoreApplicationView implementation:
-  HRESULT STDMETHODCALLTYPE
-  get_CoreWindow(winui::Core::ICoreWindow** value) override {
-    if (!core_window_)
-      return E_FAIL;
-    return core_window_.CopyTo(value);
-  }
-
-  HRESULT STDMETHODCALLTYPE
-  add_Activated(ActivatedHandler* handler,
-                EventRegistrationToken* token) override {
-    // The real component supports multiple handles but we don't yet.
-    if (activated_handler_)
-      return E_FAIL;
-    activated_handler_ = handler;
-    return S_OK;
-  }
-
-  HRESULT STDMETHODCALLTYPE
-  remove_Activated(EventRegistrationToken token) override {
-    // Chrome never unregisters handlers, so we don't care about it.
-    return S_OK;
-  }
-
-  HRESULT STDMETHODCALLTYPE get_IsMain(boolean* value) override { return S_OK; }
-
-  HRESULT STDMETHODCALLTYPE get_IsHosted(boolean* value) override {
-    return S_OK;
-  }
-
- private:
-  mswr::ComPtr<CoreWindowEmulation> core_window_;
-  mswr::ComPtr<ActivatedHandler> activated_handler_;
-};
-
-class CoreApplicationWin7Emulation
-    : public mswr::RuntimeClass<winapp::Core::ICoreApplication,
-                                winapp::Core::ICoreApplicationExit> {
- public:
-   // ICoreApplication implementation:
-
-  HRESULT STDMETHODCALLTYPE get_Id(HSTRING* value) override { return S_OK; }
-
-  HRESULT STDMETHODCALLTYPE add_Suspending(
-      winfoundtn::IEventHandler<winapp::SuspendingEventArgs*>* handler,
-      EventRegistrationToken* token) override {
-    return S_OK;
-  }
-
-  HRESULT STDMETHODCALLTYPE
-  remove_Suspending(EventRegistrationToken token) override {
-    return S_OK;
-  }
-
-  HRESULT STDMETHODCALLTYPE
-  add_Resuming(winfoundtn::IEventHandler<IInspectable*>* handler,
-               EventRegistrationToken* token) override {
-    return S_OK;
-  }
-
-  HRESULT STDMETHODCALLTYPE
-  remove_Resuming(EventRegistrationToken token) override {
-    return S_OK;
-  }
-
-  HRESULT STDMETHODCALLTYPE
-  get_Properties(winfoundtn::Collections::IPropertySet** value) override {
-    return S_OK;
-  }
-
-  HRESULT STDMETHODCALLTYPE
-  GetCurrentView(winapp::Core::ICoreApplicationView** value) override {
-    return S_OK;
-  }
-
-  HRESULT STDMETHODCALLTYPE
-  Run(winapp::Core::IFrameworkViewSource* viewSource) override {
-    HRESULT hr = viewSource->CreateView(app_view_.GetAddressOf());
-    if (FAILED(hr))
-      return hr;
-    view_emulation_ = mswr::Make<CoreApplicationViewEmulation>(
-        app_view_.Get());
-    hr = app_view_->Initialize(view_emulation_.Get());
-    if (FAILED(hr))
-      return hr;
-    mswr::ComPtr<winui::Core::ICoreWindow> core_window;
-    hr = view_emulation_->get_CoreWindow(core_window.GetAddressOf());
-    if (FAILED(hr))
-      return hr;
-    hr = app_view_->SetWindow(core_window.Get());
-    if (FAILED(hr))
-      return hr;
-    hr = app_view_->Load(NULL);
-    if (FAILED(hr))
-      return hr;
-    hr = view_emulation_->Activate();
-    if (FAILED(hr))
-      return hr;
-    return app_view_->Run();
-  }
-
-  HRESULT STDMETHODCALLTYPE RunWithActivationFactories(
-      winfoundtn::IGetActivationFactory* activationFactoryCallback) override {
-    return S_OK;
-  }
-
-  // ICoreApplicationExit implementation:
-
-  HRESULT STDMETHODCALLTYPE Exit(void) override {
-    return view_emulation_->Close();
-  }
-
-  HRESULT STDMETHODCALLTYPE
-  add_Exiting(winfoundtn::IEventHandler<IInspectable*>* handler,
-              EventRegistrationToken* token) override {
-    return S_OK;
-  }
-
-  HRESULT STDMETHODCALLTYPE
-  remove_Exiting(EventRegistrationToken token) override {
-    return S_OK;
-  }
-
- private:
-  mswr::ComPtr<winapp::Core::IFrameworkView> app_view_;
-  mswr::ComPtr<CoreApplicationViewEmulation> view_emulation_;
-};
-
-
-mswr::ComPtr<winapp::Core::ICoreApplication> InitWindows7() {
-  HRESULT hr = ::CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
-  if (FAILED(hr))
-    CHECK(false);
-  return mswr::Make<CoreApplicationWin7Emulation>();
-}
-
diff --git a/win8/viewer/metro_viewer_constants.cc b/win8/viewer/metro_viewer_constants.cc
deleted file mode 100644
index fd54fe4..0000000
--- a/win8/viewer/metro_viewer_constants.cc
+++ /dev/null
@@ -1,13 +0,0 @@
-// Copyright 2013 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 "win8/viewer/metro_viewer_constants.h"
-
-namespace win8 {
-
-const char kMetroViewerIPCChannelName[] = "viewer";
-
-const wchar_t kMetroViewerConnectVerb[] = L"connect";
-
-} // namespace win8
diff --git a/win8/viewer/metro_viewer_constants.h b/win8/viewer/metro_viewer_constants.h
deleted file mode 100644
index 560a450..0000000
--- a/win8/viewer/metro_viewer_constants.h
+++ /dev/null
@@ -1,20 +0,0 @@
-// Copyright 2013 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 WIN8_VIEWER_METRO_VIEWER_CONSTANTS_H_
-#define WIN8_VIEWER_METRO_VIEWER_CONSTANTS_H_
-
-namespace win8 {
-
-// The name of the IPC channel between the browser process and the metro viewer
-// process.
-extern const char kMetroViewerIPCChannelName[];
-
-// Tells the viewer process to simply connect back without needing to launch a
-// browser process itself.
-extern const wchar_t kMetroViewerConnectVerb[];
-
-}  // namespace win8
-
-#endif  // WIN8_VIEWER_METRO_VIEWER_CONSTANTS_H_
diff --git a/win8/viewer/metro_viewer_exports.h b/win8/viewer/metro_viewer_exports.h
deleted file mode 100644
index 61ff7d5..0000000
--- a/win8/viewer/metro_viewer_exports.h
+++ /dev/null
@@ -1,29 +0,0 @@
-// Copyright 2014 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 METRO_VIEWER_METRO_VIEWER_H_
-#define METRO_VIEWER_METRO_VIEWER_H_
-
-#if defined(COMPONENT_BUILD)
-#if defined(WIN32)
-
-#if defined(METRO_VIEWER_IMPLEMENTATION)
-#define METRO_VIEWER_EXPORT __declspec(dllexport)
-#else
-#define METRO_VIEWER_EXPORT __declspec(dllimport)
-#endif  // defined(METRO_VIEWER_IMPLEMENTATION)
-
-#else  // defined(WIN32)
-#if defined(METRO_VIEWER_IMPLEMENTATION)
-#define METRO_VIEWER_EXPORT __attribute__((visibility("default")))
-#else
-#define METRO_VIEWER_EXPORT
-#endif
-#endif
-
-#else  // defined(COMPONENT_BUILD)
-#define METRO_VIEWER_EXPORT
-#endif
-
-#endif  // METRO_VIEWER_METRO_VIEWER_H_
diff --git a/win8/viewer/metro_viewer_process_host.cc b/win8/viewer/metro_viewer_process_host.cc
deleted file mode 100644
index a3652410..0000000
--- a/win8/viewer/metro_viewer_process_host.cc
+++ /dev/null
@@ -1,346 +0,0 @@
-// Copyright (c) 2013 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 "win8/viewer/metro_viewer_process_host.h"
-
-#include <shlobj.h>
-#include <stdint.h>
-
-#include "base/command_line.h"
-#include "base/files/file_path.h"
-#include "base/files/file_util.h"
-#include "base/memory/ref_counted.h"
-#include "base/path_service.h"
-#include "base/process/process.h"
-#include "base/strings/string16.h"
-#include "base/synchronization/waitable_event.h"
-#include "base/time/time.h"
-#include "base/win/scoped_comptr.h"
-#include "base/win/windows_version.h"
-#include "ipc/ipc_channel_proxy.h"
-#include "ipc/ipc_message.h"
-#include "ipc/ipc_message_macros.h"
-#include "ui/aura/remote_window_tree_host_win.h"
-#include "ui/metro_viewer/metro_viewer_messages.h"
-#include "win8/viewer/metro_viewer_constants.h"
-
-namespace {
-
-const int kViewerProcessConnectionTimeoutSecs = 60;
-
-}  // namespace
-
-namespace win8 {
-
-// static
-MetroViewerProcessHost* MetroViewerProcessHost::instance_ = NULL;
-
-MetroViewerProcessHost::InternalMessageFilter::InternalMessageFilter(
-    MetroViewerProcessHost* owner)
-    : owner_(owner) {
-}
-
-void MetroViewerProcessHost::InternalMessageFilter::OnChannelConnected(
-    int32_t peer_pid) {
-  owner_->NotifyChannelConnected();
-}
-
-MetroViewerProcessHost::InternalMessageFilter::~InternalMessageFilter() {
-}
-
-MetroViewerProcessHost::MetroViewerProcessHost(
-    const scoped_refptr<base::SingleThreadTaskRunner>& ipc_task_runner) {
-  DCHECK(!instance_);
-  instance_ = this;
-
-  channel_ = IPC::ChannelProxy::Create(kMetroViewerIPCChannelName,
-                                       IPC::Channel::MODE_NAMED_SERVER,
-                                       this,
-                                       ipc_task_runner);
-}
-
-MetroViewerProcessHost::~MetroViewerProcessHost() {
-  if (!channel_) {
-    instance_ = NULL;
-    return;
-  }
-
-  base::ProcessId viewer_process_id = GetViewerProcessId();
-  channel_->Close();
-  if (message_filter_.get()) {
-    // Wait for the viewer process to go away.
-    if (viewer_process_id != base::kNullProcessId) {
-      base::Process viewer_process =
-          base::Process::OpenWithAccess(
-              viewer_process_id,
-              PROCESS_QUERY_INFORMATION | SYNCHRONIZE);
-      if (viewer_process.IsValid()) {
-        int exit_code;
-        viewer_process.WaitForExit(&exit_code);
-      }
-    }
-    channel_->RemoveFilter(message_filter_.get());
-  }
-  instance_ = NULL;
-}
-
-base::ProcessId MetroViewerProcessHost::GetViewerProcessId() {
-  if (channel_)
-    return channel_->GetPeerPID();
-  return base::kNullProcessId;
-}
-
-bool MetroViewerProcessHost::LaunchViewerAndWaitForConnection(
-    const base::string16& app_user_model_id) {
-  DCHECK_EQ(base::kNullProcessId, channel_->GetPeerPID());
-
-  channel_connected_event_.reset(new base::WaitableEvent(false, false));
-
-  message_filter_ = new InternalMessageFilter(this);
-  channel_->AddFilter(message_filter_.get());
-
-  if (base::win::GetVersion() >= base::win::VERSION_WIN8) {
-    base::win::ScopedComPtr<IApplicationActivationManager> activator;
-    HRESULT hr = activator.CreateInstance(CLSID_ApplicationActivationManager);
-    if (SUCCEEDED(hr)) {
-      DWORD pid = 0;
-      // Use the "connect" verb to
-      hr = activator->ActivateApplication(
-          app_user_model_id.c_str(), kMetroViewerConnectVerb, AO_NONE, &pid);
-    }
-
-    LOG_IF(ERROR, FAILED(hr)) << "Tried and failed to launch Metro Chrome. "
-                              << "hr=" << std::hex << hr;
-  } else {
-    // For Windows 7 we need to launch the viewer ourselves.
-    base::FilePath chrome_path;
-    if (!PathService::Get(base::DIR_EXE, &chrome_path))
-      return false;
-    // TODO(cpu): launch with "-ServerName:DefaultBrowserServer"
-    // note that the viewer might try to launch chrome again.
-    CHECK(false);
-  }
-
-  // Having launched the viewer process, now we wait for it to connect.
-  bool success =
-      channel_connected_event_->TimedWait(base::TimeDelta::FromSeconds(
-          kViewerProcessConnectionTimeoutSecs));
-  channel_connected_event_.reset();
-  return success;
-}
-
-bool MetroViewerProcessHost::Send(IPC::Message* msg) {
-  return channel_->Send(msg);
-}
-
-bool MetroViewerProcessHost::OnMessageReceived(
-    const IPC::Message& message) {
-  DCHECK(CalledOnValidThread());
-  bool handled = true;
-  IPC_BEGIN_MESSAGE_MAP(MetroViewerProcessHost, message)
-    IPC_MESSAGE_HANDLER(MetroViewerHostMsg_FileSaveAsDone,
-                        OnFileSaveAsDone)
-    IPC_MESSAGE_HANDLER(MetroViewerHostMsg_FileOpenDone,
-                        OnFileOpenDone)
-    IPC_MESSAGE_HANDLER(MetroViewerHostMsg_MultiFileOpenDone,
-                        OnMultiFileOpenDone)
-    IPC_MESSAGE_HANDLER(MetroViewerHostMsg_OpenURL, OnOpenURL)
-    IPC_MESSAGE_HANDLER(MetroViewerHostMsg_SearchRequest, OnHandleSearchRequest)
-    IPC_MESSAGE_HANDLER(MetroViewerHostMsg_SelectFolderDone,
-                        OnSelectFolderDone)
-    IPC_MESSAGE_HANDLER(MetroViewerHostMsg_SetTargetSurface, OnSetTargetSurface)
-    IPC_MESSAGE_HANDLER(MetroViewerHostMsg_WindowSizeChanged,
-                        OnWindowSizeChanged)
-    IPC_MESSAGE_UNHANDLED(handled = false)
-  IPC_END_MESSAGE_MAP()
-  return handled ? true :
-      aura::RemoteWindowTreeHostWin::Instance()->OnMessageReceived(message);
-}
-
-// static
-void MetroViewerProcessHost::HandleActivateDesktop(
-    const base::FilePath& path,
-    bool ash_exit) {
-  if (instance_) {
-    instance_->Send(
-        new MetroViewerHostMsg_ActivateDesktop(path, ash_exit));
-  }
-}
-
-// static
-void MetroViewerProcessHost::HandleMetroExit() {
-  if (instance_)
-    instance_->Send(new MetroViewerHostMsg_MetroExit());
-}
-
-// static
-void MetroViewerProcessHost::HandleOpenFile(
-    const base::string16& title,
-    const base::FilePath& default_path,
-    const base::string16& filter,
-    const OpenFileCompletion& on_success,
-    const FileSelectionCanceled& on_failure) {
-  if (instance_) {
-    instance_->HandleOpenFileImpl(title, default_path, filter, on_success,
-                                  on_failure);
-  }
-}
-
-// static
-void MetroViewerProcessHost::HandleOpenMultipleFiles(
-    const base::string16& title,
-    const base::FilePath& default_path,
-    const base::string16& filter,
-    const OpenMultipleFilesCompletion& on_success,
-    const FileSelectionCanceled& on_failure) {
-  if (instance_) {
-    instance_->HandleOpenMultipleFilesImpl(title, default_path, filter,
-                                           on_success, on_failure);
-  }
-}
-
-// static
-void MetroViewerProcessHost::HandleSaveFile(
-    const base::string16& title,
-    const base::FilePath& default_path,
-    const base::string16& filter,
-    int filter_index,
-    const base::string16& default_extension,
-    const SaveFileCompletion& on_success,
-    const FileSelectionCanceled& on_failure) {
-  if (instance_) {
-    instance_->HandleSaveFileImpl(title, default_path, filter, filter_index,
-                                  default_extension, on_success, on_failure);
-  }
-}
-
-// static
-void MetroViewerProcessHost::HandleSelectFolder(
-    const base::string16& title,
-    const SelectFolderCompletion& on_success,
-    const FileSelectionCanceled& on_failure) {
-  if (instance_)
-    instance_->HandleSelectFolderImpl(title, on_success, on_failure);
-}
-
-void MetroViewerProcessHost::HandleOpenFileImpl(
-    const base::string16& title,
-    const base::FilePath& default_path,
-    const base::string16& filter,
-    const OpenFileCompletion& on_success,
-    const FileSelectionCanceled& on_failure) {
-  // Can only have one of these operations in flight.
-  DCHECK(file_open_completion_callback_.is_null());
-  DCHECK(failure_callback_.is_null());
-
-  file_open_completion_callback_ = on_success;
-  failure_callback_ = on_failure;
-
-  Send(new MetroViewerHostMsg_DisplayFileOpen(title, filter, default_path,
-                                              false));
-}
-
-void MetroViewerProcessHost::HandleOpenMultipleFilesImpl(
-    const base::string16& title,
-    const base::FilePath& default_path,
-    const base::string16& filter,
-    const OpenMultipleFilesCompletion& on_success,
-    const FileSelectionCanceled& on_failure) {
-  // Can only have one of these operations in flight.
-  DCHECK(multi_file_open_completion_callback_.is_null());
-  DCHECK(failure_callback_.is_null());
-  multi_file_open_completion_callback_ = on_success;
-  failure_callback_ = on_failure;
-
-  Send(new MetroViewerHostMsg_DisplayFileOpen(title, filter, default_path,
-                                              true));
-}
-
-void MetroViewerProcessHost::HandleSaveFileImpl(
-    const base::string16& title,
-    const base::FilePath& default_path,
-    const base::string16& filter,
-    int filter_index,
-    const base::string16& default_extension,
-    const SaveFileCompletion& on_success,
-    const FileSelectionCanceled& on_failure) {
-  MetroViewerHostMsg_SaveAsDialogParams params;
-  params.title = title;
-  params.default_extension = default_extension;
-  params.filter = filter;
-  params.filter_index = filter_index;
-  params.suggested_name = default_path;
-
-  // Can only have one of these operations in flight.
-  DCHECK(file_saveas_completion_callback_.is_null());
-  DCHECK(failure_callback_.is_null());
-  file_saveas_completion_callback_ = on_success;
-  failure_callback_ = on_failure;
-
-  Send(new MetroViewerHostMsg_DisplayFileSaveAs(params));
-}
-
-void MetroViewerProcessHost::HandleSelectFolderImpl(
-    const base::string16& title,
-    const SelectFolderCompletion& on_success,
-    const FileSelectionCanceled& on_failure) {
-  // Can only have one of these operations in flight.
-  DCHECK(select_folder_completion_callback_.is_null());
-  DCHECK(failure_callback_.is_null());
-  select_folder_completion_callback_ = on_success;
-  failure_callback_ = on_failure;
-
-  Send(new MetroViewerHostMsg_DisplaySelectFolder(title));
-}
-
-void MetroViewerProcessHost::NotifyChannelConnected() {
-  if (channel_connected_event_)
-    channel_connected_event_->Signal();
-}
-
-void MetroViewerProcessHost::OnFileSaveAsDone(bool success,
-                                              const base::FilePath& filename,
-                                              int filter_index) {
-  if (success)
-    file_saveas_completion_callback_.Run(filename, filter_index, NULL);
-  else
-    failure_callback_.Run(NULL);
-  file_saveas_completion_callback_.Reset();
-  failure_callback_.Reset();
-}
-
-
-void MetroViewerProcessHost::OnFileOpenDone(bool success,
-                                            const base::FilePath& filename) {
-  if (success)
-    file_open_completion_callback_.Run(base::FilePath(filename), 0, NULL);
-  else
-    failure_callback_.Run(NULL);
-  file_open_completion_callback_.Reset();
-  failure_callback_.Reset();
-}
-
-void MetroViewerProcessHost::OnMultiFileOpenDone(
-    bool success,
-    const std::vector<base::FilePath>& files) {
-  if (success)
-    multi_file_open_completion_callback_.Run(files, NULL);
-  else
-    failure_callback_.Run(NULL);
-  multi_file_open_completion_callback_.Reset();
-  failure_callback_.Reset();
-}
-
-void MetroViewerProcessHost::OnSelectFolderDone(
-    bool success,
-    const base::FilePath& folder) {
-  if (success)
-    select_folder_completion_callback_.Run(base::FilePath(folder), 0, NULL);
-  else
-    failure_callback_.Run(NULL);
-  select_folder_completion_callback_.Reset();
-  failure_callback_.Reset();
-}
-
-}  // namespace win8
diff --git a/win8/viewer/metro_viewer_process_host.h b/win8/viewer/metro_viewer_process_host.h
deleted file mode 100644
index 2b1a56f..0000000
--- a/win8/viewer/metro_viewer_process_host.h
+++ /dev/null
@@ -1,221 +0,0 @@
-// Copyright (c) 2013 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 WIN8_VIEWER_METRO_VIEWER_PROCESS_HOST_H_
-#define WIN8_VIEWER_METRO_VIEWER_PROCESS_HOST_H_
-
-#include <stdint.h>
-
-#include "base/callback.h"
-#include "base/macros.h"
-#include "base/memory/ref_counted.h"
-#include "base/memory/scoped_ptr.h"
-#include "base/strings/string16.h"
-#include "base/threading/non_thread_safe.h"
-#include "ipc/ipc_channel_proxy.h"
-#include "ipc/ipc_listener.h"
-#include "ipc/ipc_sender.h"
-#include "ipc/message_filter.h"
-#include "ui/gfx/native_widget_types.h"
-#include "win8/viewer/metro_viewer_exports.h"
-
-namespace base {
-class SingleThreadTaskRunner;
-class WaitableEvent;
-}
-
-namespace IPC {
-class ChannelProxy;
-class Message;
-}
-
-namespace win8 {
-
-// Abstract base class for various Metro viewer process host implementations.
-class METRO_VIEWER_EXPORT MetroViewerProcessHost : public IPC::Listener,
-                                                   public IPC::Sender,
-                                                   public base::NonThreadSafe {
- public:
-  typedef base::Callback<void(const base::FilePath&, int, void*)>
-      OpenFileCompletion;
-
-  typedef base::Callback<void(const std::vector<base::FilePath>&, void*)>
-      OpenMultipleFilesCompletion;
-
-  typedef base::Callback<void(const base::FilePath&, int, void*)>
-      SaveFileCompletion;
-
-  typedef base::Callback<void(const base::FilePath&, int, void*)>
-      SelectFolderCompletion;
-
-  typedef base::Callback<void(void*)> FileSelectionCanceled;
-
-  // Initializes a viewer process host to connect to the Metro viewer process
-  // over IPC. The given task runner correspond to a thread on which
-  // IPC::Channel is created and used (e.g. IO thread). Instantly connects to
-  // the viewer process if one is already connected to |ipc_channel_name|; a
-  // viewer can otherwise be launched synchronously via
-  // LaunchViewerAndWaitForConnection().
-  explicit MetroViewerProcessHost(
-      const scoped_refptr<base::SingleThreadTaskRunner>& ipc_task_runner);
-  ~MetroViewerProcessHost() override;
-
-  // Returns the process id of the viewer process if one is connected to this
-  // host, returns base::kNullProcessId otherwise.
-  base::ProcessId GetViewerProcessId();
-
-  // Launches the viewer process associated with the given |app_user_model_id|
-  // and blocks until that viewer process connects or until a timeout is
-  // reached. Returns true if the viewer process connects before the timeout is
-  // reached. NOTE: this assumes that the app referred to by |app_user_model_id|
-  // is registered as the default browser.
-  bool LaunchViewerAndWaitForConnection(
-      const base::string16& app_user_model_id);
-
-  // Handles the activate desktop command for Metro Chrome Ash. The |ash_exit|
-  // parameter indicates whether the Ash process would be shutdown after
-  // activating the desktop.
-  static void HandleActivateDesktop(const base::FilePath& shortcut,
-                                    bool ash_exit);
-
-  // Handles the metro exit command.  Notifies the metro viewer to shutdown
-  // gracefully.
-  static void HandleMetroExit();
-
-  // Handles the open file operation for Metro Chrome Ash. The on_success
-  // callback passed in is invoked when we receive the opened file name from
-  // the metro viewer. The on failure callback is invoked on failure.
-  static void HandleOpenFile(const base::string16& title,
-                             const base::FilePath& default_path,
-                             const base::string16& filter,
-                             const OpenFileCompletion& on_success,
-                             const FileSelectionCanceled& on_failure);
-
-  // Handles the open multiple file operation for Metro Chrome Ash. The
-  // on_success callback passed in is invoked when we receive the opened file
-  // names from the metro viewer. The on failure callback is invoked on failure.
-  static void HandleOpenMultipleFiles(
-      const base::string16& title,
-      const base::FilePath& default_path,
-      const base::string16& filter,
-      const OpenMultipleFilesCompletion& on_success,
-      const FileSelectionCanceled& on_failure);
-
-  // Handles the save file operation for Metro Chrome Ash. The on_success
-  // callback passed in is invoked when we receive the saved file name from
-  // the metro viewer. The on failure callback is invoked on failure.
-  static void HandleSaveFile(const base::string16& title,
-                             const base::FilePath& default_path,
-                             const base::string16& filter,
-                             int filter_index,
-                             const base::string16& default_extension,
-                             const SaveFileCompletion& on_success,
-                             const FileSelectionCanceled& on_failure);
-
-  // Handles the select folder for Metro Chrome Ash. The on_success
-  // callback passed in is invoked when we receive the folder name from the
-  // metro viewer. The on failure callback is invoked on failure.
-  static void HandleSelectFolder(const base::string16& title,
-                                 const SelectFolderCompletion& on_success,
-                                 const FileSelectionCanceled& on_failure);
-
- protected:
-  // IPC::Sender implementation:
-  bool Send(IPC::Message* msg) override;
-
-  // IPC::Listener implementation:
-  bool OnMessageReceived(const IPC::Message& message) override;
-  void OnChannelError() override = 0;
-
- private:
-  // The following are the implementation for the corresponding static methods
-  // above, see them for descriptions.
-  void HandleOpenFileImpl(const base::string16& title,
-                          const base::FilePath& default_path,
-                          const base::string16& filter,
-                          const OpenFileCompletion& on_success,
-                          const FileSelectionCanceled& on_failure);
-  void HandleOpenMultipleFilesImpl(
-      const base::string16& title,
-      const base::FilePath& default_path,
-      const base::string16& filter,
-      const OpenMultipleFilesCompletion& on_success,
-      const FileSelectionCanceled& on_failure);
-  void HandleSaveFileImpl(const base::string16& title,
-                          const base::FilePath& default_path,
-                          const base::string16& filter,
-                          int filter_index,
-                          const base::string16& default_extension,
-                          const SaveFileCompletion& on_success,
-                          const FileSelectionCanceled& on_failure);
-  void HandleSelectFolderImpl(const base::string16& title,
-                              const SelectFolderCompletion& on_success,
-                              const FileSelectionCanceled& on_failure);
-
-  // Called over IPC by the viewer process to tell this host that it should be
-  // drawing to |target_surface|.
-  virtual void OnSetTargetSurface(gfx::NativeViewId target_surface,
-                                  float device_scale) = 0;
-
-  // Called over IPC by the viewer process to request that the url passed in be
-  // opened.
-  virtual void OnOpenURL(const base::string16& url) = 0;
-
-  // Called over IPC by the viewer process to request that the search string
-  // passed in is passed to the default search provider and a URL navigation be
-  // performed.
-  virtual void OnHandleSearchRequest(const base::string16& search_string) = 0;
-
-  // Called over IPC by the viewer process when the window size has changed.
-  virtual void OnWindowSizeChanged(uint32_t width, uint32_t height) = 0;
-
-  void NotifyChannelConnected();
-
-  // IPC message handing methods:
-  void OnFileSaveAsDone(bool success,
-                        const base::FilePath& filename,
-                        int filter_index);
-  void OnFileOpenDone(bool success, const base::FilePath& filename);
-  void OnMultiFileOpenDone(bool success,
-                           const std::vector<base::FilePath>& files);
-  void OnSelectFolderDone(bool success, const base::FilePath& folder);
-
-  // Inner message filter used to handle connection event on the IPC channel
-  // proxy's background thread. This prevents consumers of
-  // MetroViewerProcessHost from having to pump messages on their own message
-  // loop.
-  class InternalMessageFilter : public IPC::MessageFilter {
-   public:
-    InternalMessageFilter(MetroViewerProcessHost* owner);
-
-    // IPC::MessageFilter implementation.
-    void OnChannelConnected(int32_t peer_pid) override;
-
-   private:
-    ~InternalMessageFilter() override;
-
-    MetroViewerProcessHost* owner_;
-    DISALLOW_COPY_AND_ASSIGN(InternalMessageFilter);
-  };
-
-  scoped_ptr<IPC::ChannelProxy> channel_;
-  scoped_ptr<base::WaitableEvent> channel_connected_event_;
-  scoped_refptr<InternalMessageFilter> message_filter_;
-
-  static MetroViewerProcessHost* instance_;
-
-  // Saved callbacks which inform the caller about the result of the open file/
-  // save file/select operations.
-  OpenFileCompletion file_open_completion_callback_;
-  OpenMultipleFilesCompletion multi_file_open_completion_callback_;
-  SaveFileCompletion file_saveas_completion_callback_;
-  SelectFolderCompletion select_folder_completion_callback_;
-  FileSelectionCanceled failure_callback_;
-
-  DISALLOW_COPY_AND_ASSIGN(MetroViewerProcessHost);
-};
-
-}  // namespace win8
-
-#endif  // WIN8_VIEWER_METRO_VIEWER_PROCESS_HOST_H_
diff --git a/win8/win8.gyp b/win8/win8.gyp
index 4c68624..8131fa3 100644
--- a/win8/win8.gyp
+++ b/win8/win8.gyp
@@ -10,35 +10,6 @@
   ],
   'targets': [
     {
-      'target_name': 'metro_viewer_constants',
-      'type': 'static_library',
-      'include_dirs': [
-        '..',
-      ],
-      'sources': [
-        'viewer/metro_viewer_constants.cc',
-        'viewer/metro_viewer_constants.h',
-      ],
-    },
-    {
-      'target_name': 'metro_viewer',
-      'type': '<(component)',
-      'dependencies': [
-        '../base/base.gyp:base',
-        '../ipc/ipc.gyp:ipc',
-        '../ui/aura/aura.gyp:aura',
-        '../ui/metro_viewer/metro_viewer.gyp:metro_viewer_messages',
-        'metro_viewer_constants'
-      ],
-      'sources': [
-        'viewer/metro_viewer_process_host.cc',
-        'viewer/metro_viewer_process_host.h',
-      ],
-      'defines': [
-        'METRO_VIEWER_IMPLEMENTATION',
-      ],
-    },
-    {
       'target_name': 'test_support_win8',
       'type': 'static_library',
       'dependencies': [