diff options
author | jaydasika <jaydasika@chromium.org> | 2015-10-15 16:49:50 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2015-10-15 23:50:33 +0000 |
commit | f5433485551f62f0ae9361203cc39cddf71b15ce (patch) | |
tree | d65c49dc5b630579067f8869c86def9a84cbb6f2 | |
parent | d0cdbbbf6653a1ff04dba51558d582035555992b (diff) | |
download | chromium_src-f5433485551f62f0ae9361203cc39cddf71b15ce.zip chromium_src-f5433485551f62f0ae9361203cc39cddf71b15ce.tar.gz chromium_src-f5433485551f62f0ae9361203cc39cddf71b15ce.tar.bz2 |
Screen space transform from property trees for hit testing
During hit testing, we need to re-compute the screen space transform for
a layer that is not in RSLL (render surface layer list) as it is skipped
during UpdateDrawProperties and so the stored value may be outdated.
BUG=538229
CQ_INCLUDE_TRYBOTS=tryserver.blink:linux_blink_rel
Review URL: https://codereview.chromium.org/1393803003
Cr-Commit-Position: refs/heads/master@{#354405}
-rw-r--r-- | cc/trees/draw_property_utils.cc | 7 | ||||
-rw-r--r-- | cc/trees/draw_property_utils.h | 4 | ||||
-rw-r--r-- | cc/trees/layer_tree_impl.cc | 129 | ||||
-rw-r--r-- | cc/trees/layer_tree_impl_unittest.cc | 76 |
4 files changed, 177 insertions, 39 deletions
diff --git a/cc/trees/draw_property_utils.cc b/cc/trees/draw_property_utils.cc index 1554142..5969636 100644 --- a/cc/trees/draw_property_utils.cc +++ b/cc/trees/draw_property_utils.cc @@ -682,7 +682,7 @@ gfx::Rect SurfaceClipRect(const RenderSurfaceImpl* render_surface, return gfx::ToEnclosingRect(parent_clip_node->data.clip_in_target_space); } -gfx::Transform SurfaceScreenSpaceTransform( +gfx::Transform SurfaceScreenSpaceTransformFromPropertyTrees( const RenderSurfaceImpl* render_surface, const TransformTree& tree) { const TransformNode* node = tree.Node(render_surface->TransformTreeIndex()); @@ -888,8 +888,9 @@ void ComputeSurfaceDrawPropertiesUsingPropertyTrees( SurfaceDrawOpacity(render_surface, property_trees->effect_tree); draw_properties->draw_transform = SurfaceDrawTransform(render_surface, property_trees->transform_tree); - draw_properties->screen_space_transform = SurfaceScreenSpaceTransform( - render_surface, property_trees->transform_tree); + draw_properties->screen_space_transform = + SurfaceScreenSpaceTransformFromPropertyTrees( + render_surface, property_trees->transform_tree); if (render_surface->HasReplica()) { gfx::Transform replica_to_surface = ReplicaToSurfaceTransform( diff --git a/cc/trees/draw_property_utils.h b/cc/trees/draw_property_utils.h index 2200959..858f0fc 100644 --- a/cc/trees/draw_property_utils.h +++ b/cc/trees/draw_property_utils.h @@ -103,6 +103,10 @@ gfx::Transform CC_EXPORT ScreenSpaceTransformFromPropertyTrees(const LayerImpl* layer, const TransformTree& tree); +gfx::Transform CC_EXPORT SurfaceScreenSpaceTransformFromPropertyTrees( + const RenderSurfaceImpl* render_surface, + const TransformTree& tree); + void CC_EXPORT UpdatePageScaleFactorInPropertyTrees(PropertyTrees* property_trees, const LayerImpl* page_scale_layer, diff --git a/cc/trees/layer_tree_impl.cc b/cc/trees/layer_tree_impl.cc index dda446a..a77e517 100644 --- a/cc/trees/layer_tree_impl.cc +++ b/cc/trees/layer_tree_impl.cc @@ -26,6 +26,7 @@ #include "cc/layers/render_surface_impl.h" #include "cc/layers/scrollbar_layer_impl_base.h" #include "cc/resources/ui_resource_request.h" +#include "cc/trees/draw_property_utils.h" #include "cc/trees/layer_tree_host_common.h" #include "cc/trees/layer_tree_host_impl.h" #include "cc/trees/occlusion_tracker.h" @@ -1375,21 +1376,52 @@ static const LayerImpl* GetNextClippingLayer(const LayerImpl* layer) { return layer->parent(); } +static const gfx::Transform LayerScreenSpaceTransform( + const LayerImpl* layer, + const TransformTree& transform_tree, + const bool use_property_trees) { + if (!use_property_trees) + return layer->screen_space_transform(); + // When we use property trees, UpdateDrawProperties does not update the draw + // properties of a layer that is not in render surface layer list, so we need + // to compute the screen space transform. + return layer->IsDrawnRenderSurfaceLayerListMember() + ? layer->screen_space_transform() + : ScreenSpaceTransformFromPropertyTrees(layer, transform_tree); +} + +static const gfx::Transform SurfaceScreenSpaceTransform( + const LayerImpl* layer, + const TransformTree& transform_tree, + const bool use_property_trees) { + DCHECK(layer->render_surface()); + if (!use_property_trees) + return layer->render_surface()->screen_space_transform(); + return layer->IsDrawnRenderSurfaceLayerListMember() + ? layer->render_surface()->screen_space_transform() + : SurfaceScreenSpaceTransformFromPropertyTrees( + layer->render_surface(), transform_tree); +} + static bool PointIsClippedBySurfaceOrClipRect( const gfx::PointF& screen_space_point, - const LayerImpl* layer) { + const LayerImpl* layer, + const TransformTree& transform_tree, + const bool use_property_trees) { // Walk up the layer tree and hit-test any render_surfaces and any layer // clip rects that are active. for (; layer; layer = GetNextClippingLayer(layer)) { if (layer->render_surface() && !PointHitsRect(screen_space_point, - layer->render_surface()->screen_space_transform(), - layer->render_surface()->content_rect(), - NULL)) + SurfaceScreenSpaceTransform(layer, transform_tree, + use_property_trees), + layer->render_surface()->content_rect(), NULL)) return true; if (LayerClipsSubtree(layer) && - !PointHitsRect(screen_space_point, layer->screen_space_transform(), + !PointHitsRect(screen_space_point, + LayerScreenSpaceTransform(layer, transform_tree, + use_property_trees), gfx::Rect(layer->bounds()), NULL)) return true; } @@ -1401,18 +1433,21 @@ static bool PointIsClippedBySurfaceOrClipRect( static bool PointHitsLayer(const LayerImpl* layer, const gfx::PointF& screen_space_point, - float* distance_to_intersection) { + float* distance_to_intersection, + const TransformTree& transform_tree, + const bool use_property_trees) { gfx::Rect content_rect(layer->bounds()); - if (!PointHitsRect(screen_space_point, - layer->screen_space_transform(), - content_rect, - distance_to_intersection)) + if (!PointHitsRect( + screen_space_point, + LayerScreenSpaceTransform(layer, transform_tree, use_property_trees), + content_rect, distance_to_intersection)) return false; // At this point, we think the point does hit the layer, but we need to walk // up the parents to ensure that the layer was not clipped in such a way // that the hit point actually should not hit the layer. - if (PointIsClippedBySurfaceOrClipRect(screen_space_point, layer)) + if (PointIsClippedBySurfaceOrClipRect(screen_space_point, layer, + transform_tree, use_property_trees)) return false; // Skip the HUD layer. @@ -1437,17 +1472,21 @@ static void FindClosestMatchingLayer( const gfx::PointF& screen_space_point, LayerImpl* layer, const Functor& func, + const TransformTree& transform_tree, + const bool use_property_trees, FindClosestMatchingLayerDataForRecursion* data_for_recursion) { size_t children_size = layer->children().size(); for (size_t i = 0; i < children_size; ++i) { size_t index = children_size - 1 - i; FindClosestMatchingLayer(screen_space_point, layer->children()[index], func, + transform_tree, use_property_trees, data_for_recursion); } float distance_to_intersection = 0.f; if (func(layer) && - PointHitsLayer(layer, screen_space_point, &distance_to_intersection) && + PointHitsLayer(layer, screen_space_point, &distance_to_intersection, + transform_tree, use_property_trees) && ((!data_for_recursion->closest_match || distance_to_intersection > data_for_recursion->closest_distance))) { data_for_recursion->closest_distance = distance_to_intersection; @@ -1482,10 +1521,10 @@ struct FindScrollingLayerFunctor { LayerImpl* LayerTreeImpl::FindFirstScrollingLayerThatIsHitByPoint( const gfx::PointF& screen_space_point) { FindClosestMatchingLayerDataForRecursion data_for_recursion; - FindClosestMatchingLayer(screen_space_point, - root_layer(), - FindScrollingLayerFunctor(), - &data_for_recursion); + FindClosestMatchingLayer( + screen_space_point, root_layer(), FindScrollingLayerFunctor(), + property_trees_.transform_tree, settings().verify_property_trees, + &data_for_recursion); return data_for_recursion.closest_match; } @@ -1506,19 +1545,24 @@ LayerImpl* LayerTreeImpl::FindLayerThatIsHitByPoint( if (!UpdateDrawProperties(update_lcd_text)) return NULL; FindClosestMatchingLayerDataForRecursion data_for_recursion; - FindClosestMatchingLayer(screen_space_point, - root_layer(), + FindClosestMatchingLayer(screen_space_point, root_layer(), HitTestVisibleScrollableOrTouchableFunctor(), + property_trees_.transform_tree, + settings().verify_property_trees, &data_for_recursion); return data_for_recursion.closest_match; } static bool LayerHasTouchEventHandlersAt(const gfx::PointF& screen_space_point, - LayerImpl* layer_impl) { + LayerImpl* layer_impl, + const TransformTree& transform_tree, + const bool use_property_trees) { if (layer_impl->touch_event_handler_region().IsEmpty()) return false; - if (!PointHitsRegion(screen_space_point, layer_impl->screen_space_transform(), + if (!PointHitsRegion(screen_space_point, + LayerScreenSpaceTransform(layer_impl, transform_tree, + use_property_trees), layer_impl->touch_event_handler_region())) return false; @@ -1526,7 +1570,8 @@ static bool LayerHasTouchEventHandlersAt(const gfx::PointF& screen_space_point, // on the layer, but we need to walk up the parents to ensure that the layer // was not clipped in such a way that the hit point actually should not hit // the layer. - if (PointIsClippedBySurfaceOrClipRect(screen_space_point, layer_impl)) + if (PointIsClippedBySurfaceOrClipRect(screen_space_point, layer_impl, + transform_tree, use_property_trees)) return false; return true; @@ -1547,16 +1592,20 @@ LayerImpl* LayerTreeImpl::FindLayerWithWheelHandlerThatIsHitByPoint( return NULL; FindWheelEventLayerFunctor func; FindClosestMatchingLayerDataForRecursion data_for_recursion; - FindClosestMatchingLayer(screen_space_point, root_layer(), func, - &data_for_recursion); + FindClosestMatchingLayer( + screen_space_point, root_layer(), func, property_trees_.transform_tree, + settings().verify_property_trees, &data_for_recursion); return data_for_recursion.closest_match; } struct FindTouchEventLayerFunctor { bool operator()(LayerImpl* layer) const { - return LayerHasTouchEventHandlersAt(screen_space_point, layer); + return LayerHasTouchEventHandlersAt(screen_space_point, layer, + transform_tree, use_property_trees); } const gfx::PointF screen_space_point; + const TransformTree& transform_tree; + const bool use_property_trees; }; LayerImpl* LayerTreeImpl::FindLayerThatIsHitByPointInTouchHandlerRegion( @@ -1566,10 +1615,13 @@ LayerImpl* LayerTreeImpl::FindLayerThatIsHitByPointInTouchHandlerRegion( bool update_lcd_text = false; if (!UpdateDrawProperties(update_lcd_text)) return NULL; - FindTouchEventLayerFunctor func = {screen_space_point}; + FindTouchEventLayerFunctor func = {screen_space_point, + property_trees_.transform_tree, + settings().verify_property_trees}; FindClosestMatchingLayerDataForRecursion data_for_recursion; FindClosestMatchingLayer( - screen_space_point, root_layer(), func, &data_for_recursion); + screen_space_point, root_layer(), func, property_trees_.transform_tree, + settings().verify_property_trees, &data_for_recursion); return data_for_recursion.closest_match; } @@ -1580,7 +1632,9 @@ void LayerTreeImpl::RegisterSelection(const LayerSelection& selection) { static ViewportSelectionBound ComputeViewportSelectionBound( const LayerSelectionBound& layer_bound, LayerImpl* layer, - float device_scale_factor) { + float device_scale_factor, + const TransformTree& transform_tree, + const bool use_property_trees) { ViewportSelectionBound viewport_bound; viewport_bound.type = layer_bound.type; @@ -1589,12 +1643,14 @@ static ViewportSelectionBound ComputeViewportSelectionBound( gfx::PointF layer_top = layer_bound.edge_top; gfx::PointF layer_bottom = layer_bound.edge_bottom; + gfx::Transform screen_space_transform = + LayerScreenSpaceTransform(layer, transform_tree, use_property_trees); bool clipped = false; gfx::PointF screen_top = - MathUtil::MapPoint(layer->screen_space_transform(), layer_top, &clipped); - gfx::PointF screen_bottom = MathUtil::MapPoint( - layer->screen_space_transform(), layer_bottom, &clipped); + MathUtil::MapPoint(screen_space_transform, layer_top, &clipped); + gfx::PointF screen_bottom = + MathUtil::MapPoint(screen_space_transform, layer_bottom, &clipped); // MapPoint can produce points with NaN components (even when no inputs are // NaN). Since consumers of ViewportSelectionBounds may round |edge_top| or @@ -1618,12 +1674,13 @@ static ViewportSelectionBound ComputeViewportSelectionBound( gfx::PointF visibility_point = layer_bottom + visibility_offset; if (visibility_point.x() <= 0) visibility_point.set_x(visibility_point.x() + device_scale_factor); - visibility_point = MathUtil::MapPoint( - layer->screen_space_transform(), visibility_point, &clipped); + visibility_point = + MathUtil::MapPoint(screen_space_transform, visibility_point, &clipped); float intersect_distance = 0.f; viewport_bound.visible = - PointHitsLayer(layer, visibility_point, &intersect_distance); + PointHitsLayer(layer, visibility_point, &intersect_distance, + transform_tree, use_property_trees); return viewport_bound; } @@ -1634,7 +1691,8 @@ void LayerTreeImpl::GetViewportSelection(ViewportSelection* selection) { selection->start = ComputeViewportSelectionBound( selection_.start, selection_.start.layer_id ? LayerById(selection_.start.layer_id) : NULL, - device_scale_factor()); + device_scale_factor(), property_trees_.transform_tree, + settings().verify_property_trees); selection->is_editable = selection_.is_editable; selection->is_empty_text_form_control = selection_.is_empty_text_form_control; if (selection->start.type == SELECTION_BOUND_CENTER || @@ -1644,7 +1702,8 @@ void LayerTreeImpl::GetViewportSelection(ViewportSelection* selection) { selection->end = ComputeViewportSelectionBound( selection_.end, selection_.end.layer_id ? LayerById(selection_.end.layer_id) : NULL, - device_scale_factor()); + device_scale_factor(), property_trees_.transform_tree, + settings().verify_property_trees); } } diff --git a/cc/trees/layer_tree_impl_unittest.cc b/cc/trees/layer_tree_impl_unittest.cc index 182dff1..3c6a453 100644 --- a/cc/trees/layer_tree_impl_unittest.cc +++ b/cc/trees/layer_tree_impl_unittest.cc @@ -1456,7 +1456,8 @@ TEST_F(LayerTreeImplTest, EXPECT_EQ(gfx::Rect(test_layer->bounds()), test_layer->visible_layer_rect()); // Hit checking for a point outside the layer should return a null pointer - // (the root layer does not draw content, so it will not be tested either). + // (the root layer does not have a touch event handler, so it will not be + // tested either). gfx::PointF test_point(76.f, 76.f); test_point = gfx::ScalePoint(test_point, device_scale_factor * page_scale_factor); @@ -1711,6 +1712,79 @@ TEST_F(LayerTreeImplTest, HitCheckingTouchHandlerOverlappingRegions) { EXPECT_FALSE(result_layer); } +TEST_F(LayerTreeImplTest, HitTestingTouchHandlerRegionsForLayerThatIsNotDrawn) { + scoped_ptr<LayerImpl> root = LayerImpl::Create(host_impl().active_tree(), 1); + + gfx::Transform identity_matrix; + gfx::Point3F transform_origin; + SetLayerPropertiesForTesting(root.get(), identity_matrix, transform_origin, + gfx::PointF(), gfx::Size(100, 100), true, false, + true); + root->SetDrawsContent(true); + { + Region touch_handler_region(gfx::Rect(10, 10, 30, 30)); + gfx::PointF position; + gfx::Size bounds(50, 50); + scoped_ptr<LayerImpl> test_layer = + LayerImpl::Create(host_impl().active_tree(), 12345); + SetLayerPropertiesForTesting(test_layer.get(), identity_matrix, + transform_origin, position, bounds, true, + false, false); + + test_layer->SetDrawsContent(false); + test_layer->SetTouchEventHandlerRegion(touch_handler_region); + root->AddChild(test_layer.Pass()); + } + host_impl().SetViewportSize(root->bounds()); + host_impl().active_tree()->SetRootLayer(root.Pass()); + host_impl().UpdateNumChildrenAndDrawPropertiesForActiveTree(); + + LayerImpl* test_layer = + host_impl().active_tree()->root_layer()->children()[0]; + // As test_layer doesn't draw content, the layer list of root's render surface + // should contain only the root layer. + ASSERT_EQ(1u, RenderSurfaceLayerList().size()); + ASSERT_EQ(1u, root_layer()->render_surface()->layer_list().size()); + + // Hit testing for a point outside the test layer should return null pointer. + // We also implicitly check that the updated screen space transform of a layer + // that is not in drawn render surface layer list (test_layer) is used during + // hit testing (becuase the point is inside test_layer with respect to the old + // screen space transform). + gfx::PointF test_point(24.f, 24.f); + test_layer->SetPosition(gfx::PointF(25.f, 25.f)); + gfx::Transform expected_screen_space_transform; + expected_screen_space_transform.Translate(25.f, 25.f); + + host_impl().active_tree()->property_trees()->needs_rebuild = true; + host_impl().active_tree()->BuildPropertyTreesForTesting(); + LayerImpl* result_layer = + host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion( + test_point); + EXPECT_FALSE(result_layer); + EXPECT_FALSE(test_layer->IsDrawnRenderSurfaceLayerListMember()); + EXPECT_TRANSFORMATION_MATRIX_EQ(expected_screen_space_transform, + test_layer->screen_space_transform()); + + // We change the position of the test layer such that the test point is now + // inside the test_layer. + test_layer = host_impl().active_tree()->root_layer()->children()[0]; + test_layer->SetPosition(gfx::PointF(10.f, 10.f)); + expected_screen_space_transform.MakeIdentity(); + expected_screen_space_transform.Translate(10.f, 10.f); + + host_impl().active_tree()->property_trees()->needs_rebuild = true; + host_impl().active_tree()->BuildPropertyTreesForTesting(); + result_layer = + host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion( + test_point); + ASSERT_TRUE(result_layer); + ASSERT_EQ(test_layer, result_layer); + EXPECT_FALSE(result_layer->IsDrawnRenderSurfaceLayerListMember()); + EXPECT_TRANSFORMATION_MATRIX_EQ(expected_screen_space_transform, + result_layer->screen_space_transform()); +} + TEST_F(LayerTreeImplTest, SelectionBoundsForSingleLayer) { int root_layer_id = 12345; scoped_ptr<LayerImpl> root = |