Add initial CC support for scroll-blocks-on

When 'scroll-blocks-on: scroll-event' is applied anywhere in the scroll ancestor tree where is a scroll event handler, force the scroll to be executed on the main thread.  Note that this is still experimental.  We'll be at least adding a timeout mechanism to this to mitigate the risk of improper usage.

When 'scroll-blocks-on: wheel-event' is NOT applied (it's on by default), ignore the existence of wheel event handlers (allowing scrolling to run freely on impl).

When 'scroll-blocks-on: start-touch' is NOT applied (it's on by default), suppress sending touch events to blink.  Eventually we'll make this smarter - sending async touch events that don't block scroll.

Depends on blink change https://src.chromium.org/viewvc/blink?view=rev&revision=188230

BUG=347272

Review URL: https://codereview.chromium.org/784463002

Cr-Commit-Position: refs/heads/master@{#314765}
diff --git a/cc/trees/layer_tree_host_impl.cc b/cc/trees/layer_tree_host_impl.cc
index b5509a7..f51c61a 100644
--- a/cc/trees/layer_tree_host_impl.cc
+++ b/cc/trees/layer_tree_host_impl.cc
@@ -467,16 +467,39 @@
   return layer_impl != NULL;
 }
 
-bool LayerTreeHostImpl::HaveTouchEventHandlersAt(
-    const gfx::Point& viewport_point) {
+static LayerImpl* NextScrollLayer(LayerImpl* layer) {
+  if (LayerImpl* scroll_parent = layer->scroll_parent())
+    return scroll_parent;
+  return layer->parent();
+}
 
+static ScrollBlocksOn EffectiveScrollBlocksOn(LayerImpl* layer) {
+  ScrollBlocksOn blocks = ScrollBlocksOnNone;
+  for (; layer; layer = NextScrollLayer(layer)) {
+    blocks |= layer->scroll_blocks_on();
+  }
+  return blocks;
+}
+
+bool LayerTreeHostImpl::DoTouchEventsBlockScrollAt(
+    const gfx::Point& viewport_point) {
   gfx::PointF device_viewport_point =
       gfx::ScalePoint(viewport_point, device_scale_factor_);
 
+  // First check if scrolling at this point is required to block on any
+  // touch event handlers.  Note that we must start at the innermost layer
+  // (as opposed to only the layer found to contain a touch handler region
+  // below) to ensure all relevant scroll-blocks-on values are applied.
   LayerImpl* layer_impl =
-      active_tree_->FindLayerThatIsHitByPointInTouchHandlerRegion(
-          device_viewport_point);
+      active_tree_->FindLayerThatIsHitByPoint(device_viewport_point);
+  ScrollBlocksOn blocking = EffectiveScrollBlocksOn(layer_impl);
+  if (!(blocking & ScrollBlocksOnStartTouch))
+    return false;
 
+  // Now determine if there are actually any handlers at that point.
+  // TODO(rbyers): Consider also honoring touch-action (crbug.com/347272).
+  layer_impl = active_tree_->FindLayerThatIsHitByPointInTouchHandlerRegion(
+      device_viewport_point);
   return layer_impl != NULL;
 }
 
@@ -2276,12 +2299,6 @@
   input_handler_client_ = client;
 }
 
-static LayerImpl* NextScrollLayer(LayerImpl* layer) {
-  if (LayerImpl* scroll_parent = layer->scroll_parent())
-    return scroll_parent;
-  return layer->parent();
-}
-
 LayerImpl* LayerTreeHostImpl::FindScrollLayerForDeviceViewportPoint(
     const gfx::PointF& device_viewport_point,
     InputHandler::ScrollInputType type,
@@ -2290,12 +2307,15 @@
     bool* optional_has_ancestor_scroll_handler) const {
   DCHECK(scroll_on_main_thread);
 
+  ScrollBlocksOn block_mode = EffectiveScrollBlocksOn(layer_impl);
+
   // Walk up the hierarchy and look for a scrollable layer.
   LayerImpl* potentially_scrolling_layer_impl = NULL;
   for (; layer_impl; layer_impl = NextScrollLayer(layer_impl)) {
     // The content layer can also block attempts to scroll outside the main
     // thread.
-    ScrollStatus status = layer_impl->TryScroll(device_viewport_point, type);
+    ScrollStatus status =
+        layer_impl->TryScroll(device_viewport_point, type, block_mode);
     if (status == ScrollOnMainThread) {
       *scroll_on_main_thread = true;
       return NULL;
@@ -2305,7 +2325,8 @@
     if (!scroll_layer_impl)
       continue;
 
-    status = scroll_layer_impl->TryScroll(device_viewport_point, type);
+    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 == ScrollOnMainThread) {
       *scroll_on_main_thread = true;