Chromium Code Reviews| Index: cc/trees/layer_tree_host_common.cc |
| diff --git a/cc/trees/layer_tree_host_common.cc b/cc/trees/layer_tree_host_common.cc |
| index ba92d8d546b1f18879f45cafd2f67e21b4769858..4fdc6a4543f97764174a82c77faebe2038a9c570 100644 |
| --- a/cc/trees/layer_tree_host_common.cc |
| +++ b/cc/trees/layer_tree_host_common.cc |
| @@ -1174,6 +1174,7 @@ static void PreCalculateMetaInformation( |
| bool has_delegated_content = layer->HasDelegatedContent(); |
| int num_descendants_that_draw_content = 0; |
| + layer->draw_properties().is_in_layer_list = false; |
| layer->draw_properties().sorted_for_recursion = false; |
| layer->draw_properties().has_child_with_a_scroll_parent = false; |
| @@ -2011,8 +2012,10 @@ static void CalculateDrawPropertiesInternal( |
| // and should be included in the sorting process. |
| size_t sorting_start_index = descendants.size(); |
| - if (!LayerShouldBeSkipped(layer, layer_is_drawn)) |
| + if (!LayerShouldBeSkipped(layer, layer_is_drawn)) { |
| + layer_draw_properties.is_in_layer_list = true; |
| descendants.push_back(layer); |
| + } |
| // Any layers that are appended after this point may need to be sorted if we |
| // visit the children out of order. |
| @@ -2373,7 +2376,8 @@ void LayerTreeHostCommon::CalculateDrawProperties( |
| static bool PointHitsRect( |
| const gfx::PointF& screen_space_point, |
| const gfx::Transform& local_space_to_screen_space_transform, |
| - const gfx::RectF& local_space_rect) { |
| + const gfx::RectF& local_space_rect, |
| + float* distance_to_camera) { |
| // If the transform is not invertible, then assume that this point doesn't hit |
| // this rect. |
| gfx::Transform inverse_local_space_to_screen_space( |
| @@ -2385,15 +2389,29 @@ static bool PointHitsRect( |
| // Transform the hit test point from screen space to the local space of the |
| // given rect. |
| bool clipped = false; |
| - gfx::PointF hit_test_point_in_local_space = MathUtil::ProjectPoint( |
| + gfx::Point3F planar_point = MathUtil::ProjectPoint3D( |
| inverse_local_space_to_screen_space, screen_space_point, &clipped); |
| + gfx::PointF hit_test_point_in_local_space = |
| + gfx::PointF(planar_point.x(), planar_point.y()); |
| // If ProjectPoint could not project to a valid value, then we assume that |
| // this point doesn't hit this rect. |
| if (clipped) |
| return false; |
| - return local_space_rect.Contains(hit_test_point_in_local_space); |
| + if (!local_space_rect.Contains(hit_test_point_in_local_space)) |
| + return false; |
| + |
| + if (distance_to_camera) { |
| + // To compute the distance to the camera, we have to take the planar point |
| + // and pull it back to world space and compute the displacement along the |
| + // z-axis. |
| + gfx::Point3F planar_point_in_screen_space(planar_point); |
| + local_space_to_screen_space_transform.TransformPoint(&planar_point); |
| + *distance_to_camera = planar_point_in_screen_space.z(); |
| + } |
| + |
| + return true; |
| } |
| static bool PointHitsRegion(const gfx::PointF& screen_space_point, |
| @@ -2439,7 +2457,8 @@ static bool PointIsClippedBySurfaceOrClipRect( |
| !PointHitsRect( |
| screen_space_point, |
| current_layer->render_surface()->screen_space_transform(), |
| - current_layer->render_surface()->content_rect())) |
| + current_layer->render_surface()->content_rect(), |
| + NULL)) |
| return true; |
| // Note that drawable content rects are actually in target surface space, so |
| @@ -2450,7 +2469,8 @@ static bool PointIsClippedBySurfaceOrClipRect( |
| !PointHitsRect( |
| screen_space_point, |
| render_target->render_surface()->screen_space_transform(), |
| - current_layer->drawable_content_rect())) |
| + current_layer->drawable_content_rect(), |
| + NULL)) |
| return true; |
| current_layer = current_layer->parent(); |
| @@ -2462,10 +2482,13 @@ static bool PointIsClippedBySurfaceOrClipRect( |
| } |
| static bool PointHitsLayer(LayerImpl* layer, |
| - const gfx::PointF& screen_space_point) { |
| + const gfx::PointF& screen_space_point, |
| + float* distance_to_intersection) { |
| gfx::RectF content_rect(layer->content_bounds()); |
| - if (!PointHitsRect( |
| - screen_space_point, layer->screen_space_transform(), content_rect)) |
| + if (!PointHitsRect(screen_space_point, |
| + layer->screen_space_transform(), |
| + content_rect, |
| + distance_to_intersection)) |
| return false; |
| // At this point, we think the point does hit the layer, but we need to walk |
| @@ -2481,87 +2504,83 @@ static bool PointHitsLayer(LayerImpl* layer, |
| return true; |
| } |
| -LayerImpl* LayerTreeHostCommon::FindFirstScrollingLayerThatIsHitByPoint( |
| - const gfx::PointF& screen_space_point, |
| - const LayerImplList& render_surface_layer_list) { |
| - typedef LayerIterator<LayerImpl> LayerIteratorType; |
| - LayerIteratorType end = LayerIteratorType::End(&render_surface_layer_list); |
| - for (LayerIteratorType it = |
| - LayerIteratorType::Begin(&render_surface_layer_list); |
| - it != end; |
| - ++it) { |
| - // We don't want to consider render_surfaces for hit testing. |
| - if (!it.represents_itself()) |
| - continue; |
| - |
| - LayerImpl* current_layer = (*it); |
| - if (!PointHitsLayer(current_layer, screen_space_point)) |
| - continue; |
| +struct FindClosestMatchingLayerDataForRecursion { |
| + FindClosestMatchingLayerDataForRecursion() |
| + : closest_match(NULL), closest_distance(0.f), found_match(false) {} |
| + LayerImpl* closest_match; |
| + float closest_distance; |
| + bool found_match; |
| +}; |
| - if (current_layer->scrollable()) |
| - return current_layer; |
| +template <typename Functor> |
| +static void FindClosestMatchingLayer( |
| + const gfx::PointF& screen_space_point, |
| + LayerImpl* layer, |
| + const Functor& func, |
| + FindClosestMatchingLayerDataForRecursion* data_for_recursion) { |
| + for (int i = layer->children().size() - 1; i >= 0; --i) { |
| + FindClosestMatchingLayer( |
| + screen_space_point, layer->children()[i], func, data_for_recursion); |
| + } |
| + |
| + float distance_to_intersection = 0.f; |
| + if (func(layer) && |
| + PointHitsLayer(layer, screen_space_point, &distance_to_intersection) && |
| + ((!data_for_recursion->found_match || |
| + distance_to_intersection < data_for_recursion->closest_distance))) { |
| + data_for_recursion->found_match = true; |
| + data_for_recursion->closest_distance = distance_to_intersection; |
| + data_for_recursion->closest_match = layer; |
| } |
| - |
| - return NULL; |
| } |
| -LayerImpl* LayerTreeHostCommon::FindLayerThatIsHitByPoint( |
| - const gfx::PointF& screen_space_point, |
| - const LayerImplList& render_surface_layer_list) { |
| - LayerImpl* found_layer = NULL; |
| - |
| - typedef LayerIterator<LayerImpl> LayerIteratorType; |
| - LayerIteratorType end = LayerIteratorType::End(&render_surface_layer_list); |
| - for (LayerIteratorType |
| - it = LayerIteratorType::Begin(&render_surface_layer_list); |
| - it != end; |
| - ++it) { |
| - // We don't want to consider render_surfaces for hit testing. |
| - if (!it.represents_itself()) |
| - continue; |
| +struct FindScrollingLayerFunctor { |
| + bool operator()(LayerImpl* layer) const { return layer->scrollable(); } |
| +}; |
| - LayerImpl* current_layer = (*it); |
| - if (!PointHitsLayer(current_layer, screen_space_point)) |
| - continue; |
| +LayerImpl* LayerTreeHostCommon::FindFirstScrollingLayerThatIsHitByPoint( |
| + const gfx::PointF& screen_space_point, |
| + LayerImpl* root) { |
| + FindClosestMatchingLayerDataForRecursion data_for_recursion; |
| + FindClosestMatchingLayer(screen_space_point, |
| + root, |
| + FindScrollingLayerFunctor(), |
| + &data_for_recursion); |
| + return data_for_recursion.closest_match; |
| +} |
| - found_layer = current_layer; |
| - break; |
| +struct HitTestVisibleFunctor { |
| + bool operator()(LayerImpl* layer) const { |
| + return layer->draw_properties().is_in_layer_list || |
|
enne (OOO)
2014/05/06 20:30:58
What is the "is_in_layer_list" function standing i
|
| + !layer->touch_event_handler_region().IsEmpty() || |
| + layer->have_wheel_event_handlers(); |
| } |
| +}; |
| - // This can potentially return NULL, which means the screen_space_point did |
| - // not successfully hit test any layers, not even the root layer. |
| - return found_layer; |
| +LayerImpl* LayerTreeHostCommon::FindLayerThatIsHitByPoint( |
| + const gfx::PointF& screen_space_point, |
| + LayerImpl* root) { |
| + FindClosestMatchingLayerDataForRecursion data_for_recursion; |
| + FindClosestMatchingLayer( |
| + screen_space_point, root, HitTestVisibleFunctor(), &data_for_recursion); |
| + return data_for_recursion.closest_match; |
| } |
| +struct FindTouchEventLayerFunctor { |
| + bool operator()(LayerImpl* layer) const { |
| + return LayerTreeHostCommon::LayerHasTouchEventHandlersAt(screen_space_point, |
| + layer); |
| + } |
| + const gfx::PointF screen_space_point; |
| +}; |
| + |
| LayerImpl* LayerTreeHostCommon::FindLayerThatIsHitByPointInTouchHandlerRegion( |
| const gfx::PointF& screen_space_point, |
| - const LayerImplList& render_surface_layer_list) { |
| - typedef LayerIterator<LayerImpl> LayerIteratorType; |
| - LayerIteratorType end = LayerIteratorType::End(&render_surface_layer_list); |
| - for (LayerIteratorType it = |
| - LayerIteratorType::Begin(&render_surface_layer_list); |
| - it != end; |
| - ++it) { |
| - // We don't want to consider render_surfaces for hit testing. |
| - if (!it.represents_itself()) |
| - continue; |
| - |
| - LayerImpl* current_layer = (*it); |
| - if (!PointHitsLayer(current_layer, screen_space_point)) |
| - continue; |
| - |
| - if (LayerTreeHostCommon::LayerHasTouchEventHandlersAt(screen_space_point, |
| - current_layer)) |
| - return current_layer; |
| - |
| - // Note that we could stop searching if we hit a layer we know to be |
| - // opaque to hit-testing, but knowing that reliably is tricky (eg. due to |
| - // CSS pointer-events: none). Also blink has an optimization for the |
| - // common case of an entire document having handlers where it doesn't |
| - // report any rects for child layers (since it knows they can't exceed |
| - // the document bounds). |
| - } |
| - return NULL; |
| + LayerImpl* root) { |
| + FindTouchEventLayerFunctor func = {screen_space_point}; |
| + FindClosestMatchingLayerDataForRecursion data_for_recursion; |
| + FindClosestMatchingLayer(screen_space_point, root, func, &data_for_recursion); |
| + return data_for_recursion.closest_match; |
| } |
| bool LayerTreeHostCommon::LayerHasTouchEventHandlersAt( |
| @@ -2586,4 +2605,5 @@ bool LayerTreeHostCommon::LayerHasTouchEventHandlersAt( |
| return true; |
| } |
| + |
| } // namespace cc |