summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjaydasika <jaydasika@chromium.org>2015-10-15 16:49:50 -0700
committerCommit bot <commit-bot@chromium.org>2015-10-15 23:50:33 +0000
commitf5433485551f62f0ae9361203cc39cddf71b15ce (patch)
treed65c49dc5b630579067f8869c86def9a84cbb6f2
parentd0cdbbbf6653a1ff04dba51558d582035555992b (diff)
downloadchromium_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.cc7
-rw-r--r--cc/trees/draw_property_utils.h4
-rw-r--r--cc/trees/layer_tree_impl.cc129
-rw-r--r--cc/trees/layer_tree_impl_unittest.cc76
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 =