0

Add API for hit testing layer_impl touchEventHandlerRegions from the host

These APIs will be used for hit testing touchEvents on the compositor. Currently
all touch events coming through input_event_filter return DidNotHandle. Using this check
we will be able to check the touch Ppoint against the touchEventHandlerRegion in all
layer_impls and return DropEvent if there are no hits.

BUG=135818


Review URL: https://chromiumcodereview.appspot.com/11402002

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@168294 0039d316-1c4b-4281-b951-d872f2087c98
This commit is contained in:
yusufo@chromium.org
2012-11-16 21:42:22 +00:00
parent ccc65553d5
commit 2f1acc2635
7 changed files with 487 additions and 1 deletions

@ -11,6 +11,7 @@
namespace gfx {
class Point;
class PointF;
class Vector2d;
}
@ -64,6 +65,8 @@ public:
// Request another callback to InputHandler::animate().
virtual void scheduleAnimation() = 0;
virtual bool haveTouchEventHandlersAt(const gfx::Point&) = 0;
protected:
InputHandlerClient() { }
virtual ~InputHandlerClient() { }

@ -11,6 +11,7 @@
#include "cc/math_util.h"
#include "cc/render_surface.h"
#include "cc/render_surface_impl.h"
#include "ui/gfx/point_conversions.h"
#include "ui/gfx/rect_conversions.h"
#include <algorithm>
#include <public/WebTransformationMatrix.h>
@ -872,6 +873,24 @@ static bool pointHitsRect(const gfx::PointF& screenSpacePoint, const WebTransfor
return localSpaceRect.Contains(hitTestPointInLocalSpace);
}
static bool pointHitsRegion(gfx::PointF screenSpacePoint, const WebTransformationMatrix& screenSpaceTransform, const Region& layerSpaceRegion, float layerContentScaleX, float layerContentScaleY)
{
// If the transform is not invertible, then assume that this point doesn't hit this region.
if (!screenSpaceTransform.isInvertible())
return false;
// Transform the hit test point from screen space to the local space of the given region.
bool clipped = false;
gfx::PointF hitTestPointInContentSpace = MathUtil::projectPoint(screenSpaceTransform.inverse(), screenSpacePoint, clipped);
gfx::PointF hitTestPointInLayerSpace = gfx::ScalePoint(hitTestPointInContentSpace, 1 / layerContentScaleX, 1 / layerContentScaleY);
// If projectPoint could not project to a valid value, then we assume that this point doesn't hit this region.
if (clipped)
return false;
return layerSpaceRegion.Contains(gfx::ToRoundedPoint(hitTestPointInLayerSpace));
}
static bool pointIsClippedBySurfaceOrClipRect(const gfx::PointF& screenSpacePoint, LayerImpl* layer)
{
LayerImpl* currentLayer = layer;
@ -926,4 +945,38 @@ LayerImpl* LayerTreeHostCommon::findLayerThatIsHitByPoint(const gfx::PointF& scr
return foundLayer;
}
LayerImpl* LayerTreeHostCommon::findLayerThatIsHitByPointInTouchHandlerRegion(const gfx::PointF& screenSpacePoint, std::vector<LayerImpl*>& renderSurfaceLayerList)
{
LayerImpl* foundLayer = 0;
typedef LayerIterator<LayerImpl, std::vector<LayerImpl*>, RenderSurfaceImpl, LayerIteratorActions::FrontToBack> LayerIteratorType;
LayerIteratorType end = LayerIteratorType::end(&renderSurfaceLayerList);
for (LayerIteratorType it = LayerIteratorType::begin(&renderSurfaceLayerList); it != end; ++it) {
// We don't want to consider renderSurfaces for hit testing.
if (!it.representsItself())
continue;
LayerImpl* currentLayer = (*it);
if (currentLayer->touchEventHandlerRegion().IsEmpty())
continue;
if (!pointHitsRegion(screenSpacePoint, currentLayer->screenSpaceTransform(), currentLayer->touchEventHandlerRegion(), currentLayer->contentsScaleX(), currentLayer->contentsScaleY()))
continue;
// At this point, we think the point does hit the touch event handler region 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(screenSpacePoint, currentLayer))
continue;
foundLayer = currentLayer;
break;
}
// This can potentially return 0, which means the screenSpacePoint did not successfully hit test any layers, not even the root layer.
return foundLayer;
}
} // namespace cc

@ -28,6 +28,8 @@ public:
// Performs hit testing for a given renderSurfaceLayerList.
static LayerImpl* findLayerThatIsHitByPoint(const gfx::PointF& screenSpacePoint, std::vector<LayerImpl*>& renderSurfaceLayerList);
static LayerImpl* findLayerThatIsHitByPointInTouchHandlerRegion(const gfx::PointF& screenSpacePoint, std::vector<LayerImpl*>& renderSurfaceLayerList);
template<typename LayerType> static bool renderSurfaceContributesToTarget(LayerType*, int targetSurfaceLayerID);
// Returns a layer with the given id if one exists in the subtree starting

@ -16,6 +16,7 @@
#include "cc/test/animation_test_common.h"
#include "cc/test/geometry_test_utils.h"
#include "cc/thread.h"
#include "ui/gfx/size_conversions.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include <public/WebTransformationMatrix.h>
@ -3069,7 +3070,7 @@ TEST(LayerTreeHostCommonTest, verifyHitTestingForMultiClippedRotatedLayer)
bounds = gfx::Size(80, 80);
setLayerPropertiesForTesting(child.get(), identityMatrix, identityMatrix, anchor, position, bounds, false);
child->setMasksToBounds(true);
WebTransformationMatrix rotation45DegreesAboutCorner;
rotation45DegreesAboutCorner.rotate3d(0, 0, 45);
@ -3417,6 +3418,412 @@ TEST(LayerTreeHostCommonTest, verifyHitTestingForMultipleLayerLists)
EXPECT_EQ(4, resultLayer->id());
}
TEST(LayerTreeHostCommonTest, verifyHitCheckingTouchHandlerRegionsForEmptyLayerList)
{
// Hit checking on an empty renderSurfaceLayerList should return a null pointer.
std::vector<LayerImpl*> renderSurfaceLayerList;
gfx::Point testPoint(0, 0);
LayerImpl* resultLayer = LayerTreeHostCommon::findLayerThatIsHitByPointInTouchHandlerRegion(testPoint, renderSurfaceLayerList);
EXPECT_FALSE(resultLayer);
testPoint = gfx::Point(10, 20);
resultLayer = LayerTreeHostCommon::findLayerThatIsHitByPointInTouchHandlerRegion(testPoint, renderSurfaceLayerList);
EXPECT_FALSE(resultLayer);
}
TEST(LayerTreeHostCommonTest, verifyHitCheckingTouchHandlerRegionsForSingleLayer)
{
scoped_ptr<LayerImpl> root = LayerImpl::create(12345);
WebTransformationMatrix identityMatrix;
Region touchHandlerRegion(gfx::Rect(10, 10, 50, 50));
gfx::PointF anchor(0, 0);
gfx::PointF position(0, 0);
gfx::Size bounds(100, 100);
setLayerPropertiesForTesting(root.get(), identityMatrix, identityMatrix, anchor, position, bounds, false);
root->setDrawsContent(true);
std::vector<LayerImpl*> renderSurfaceLayerList;
int dummyMaxTextureSize = 512;
LayerTreeHostCommon::calculateDrawTransforms(root.get(), root->bounds(), 1, 1, 0, dummyMaxTextureSize, renderSurfaceLayerList);
// Sanity check the scenario we just created.
ASSERT_EQ(1u, renderSurfaceLayerList.size());
ASSERT_EQ(1u, root->renderSurface()->layerList().size());
// Hit checking for any point should return a null pointer for a layer without any touch event handler regions.
gfx::Point testPoint(11, 11);
LayerImpl* resultLayer = LayerTreeHostCommon::findLayerThatIsHitByPointInTouchHandlerRegion(testPoint, renderSurfaceLayerList);
EXPECT_FALSE(resultLayer);
root->setTouchEventHandlerRegion(touchHandlerRegion);
// Hit checking for a point outside the layer should return a null pointer.
testPoint = gfx::Point(101, 101);
resultLayer = LayerTreeHostCommon::findLayerThatIsHitByPointInTouchHandlerRegion(testPoint, renderSurfaceLayerList);
EXPECT_FALSE(resultLayer);
testPoint = gfx::Point(-1, -1);
resultLayer = LayerTreeHostCommon::findLayerThatIsHitByPointInTouchHandlerRegion(testPoint, renderSurfaceLayerList);
EXPECT_FALSE(resultLayer);
// Hit checking for a point inside the layer, but outside the touch handler region should return a null pointer.
testPoint = gfx::Point(1, 1);
resultLayer = LayerTreeHostCommon::findLayerThatIsHitByPointInTouchHandlerRegion(testPoint, renderSurfaceLayerList);
EXPECT_FALSE(resultLayer);
testPoint = gfx::Point(99, 99);
resultLayer = LayerTreeHostCommon::findLayerThatIsHitByPointInTouchHandlerRegion(testPoint, renderSurfaceLayerList);
EXPECT_FALSE(resultLayer);
// Hit checking for a point inside the touch event handler region should return the root layer.
testPoint = gfx::Point(11, 11);
resultLayer = LayerTreeHostCommon::findLayerThatIsHitByPointInTouchHandlerRegion(testPoint, renderSurfaceLayerList);
ASSERT_TRUE(resultLayer);
EXPECT_EQ(12345, resultLayer->id());
testPoint = gfx::Point(59, 59);
resultLayer = LayerTreeHostCommon::findLayerThatIsHitByPointInTouchHandlerRegion(testPoint, renderSurfaceLayerList);
ASSERT_TRUE(resultLayer);
EXPECT_EQ(12345, resultLayer->id());
}
TEST(LayerTreeHostCommonTest, verifyHitCheckingTouchHandlerRegionsForUninvertibleTransform)
{
scoped_ptr<LayerImpl> root = LayerImpl::create(12345);
WebTransformationMatrix uninvertibleTransform;
uninvertibleTransform.setM11(0);
uninvertibleTransform.setM22(0);
uninvertibleTransform.setM33(0);
uninvertibleTransform.setM44(0);
ASSERT_FALSE(uninvertibleTransform.isInvertible());
WebTransformationMatrix identityMatrix;
Region touchHandlerRegion(gfx::Rect(10, 10, 50, 50));
gfx::PointF anchor(0, 0);
gfx::PointF position(0, 0);
gfx::Size bounds(100, 100);
setLayerPropertiesForTesting(root.get(), uninvertibleTransform, identityMatrix, anchor, position, bounds, false);
root->setDrawsContent(true);
root->setTouchEventHandlerRegion(touchHandlerRegion);
std::vector<LayerImpl*> renderSurfaceLayerList;
int dummyMaxTextureSize = 512;
LayerTreeHostCommon::calculateDrawTransforms(root.get(), root->bounds(), 1, 1, 0, dummyMaxTextureSize, renderSurfaceLayerList);
// Sanity check the scenario we just created.
ASSERT_EQ(1u, renderSurfaceLayerList.size());
ASSERT_EQ(1u, root->renderSurface()->layerList().size());
ASSERT_FALSE(root->screenSpaceTransform().isInvertible());
// Hit checking any point should not hit the touch handler region on the layer. If the invertible matrix is
// accidentally ignored and treated like an identity, then the hit testing will
// incorrectly hit the layer when it shouldn't.
gfx::Point testPoint(1, 1);
LayerImpl* resultLayer = LayerTreeHostCommon::findLayerThatIsHitByPointInTouchHandlerRegion(testPoint, renderSurfaceLayerList);
EXPECT_FALSE(resultLayer);
testPoint = gfx::Point(10, 10);
resultLayer = LayerTreeHostCommon::findLayerThatIsHitByPointInTouchHandlerRegion(testPoint, renderSurfaceLayerList);
EXPECT_FALSE(resultLayer);
testPoint = gfx::Point(10, 30);
resultLayer = LayerTreeHostCommon::findLayerThatIsHitByPointInTouchHandlerRegion(testPoint, renderSurfaceLayerList);
EXPECT_FALSE(resultLayer);
testPoint = gfx::Point(50, 50);
resultLayer = LayerTreeHostCommon::findLayerThatIsHitByPointInTouchHandlerRegion(testPoint, renderSurfaceLayerList);
EXPECT_FALSE(resultLayer);
testPoint = gfx::Point(67, 48);
resultLayer = LayerTreeHostCommon::findLayerThatIsHitByPointInTouchHandlerRegion(testPoint, renderSurfaceLayerList);
EXPECT_FALSE(resultLayer);
testPoint = gfx::Point(99, 99);
resultLayer = LayerTreeHostCommon::findLayerThatIsHitByPointInTouchHandlerRegion(testPoint, renderSurfaceLayerList);
EXPECT_FALSE(resultLayer);
testPoint = gfx::Point(-1, -1);
resultLayer = LayerTreeHostCommon::findLayerThatIsHitByPointInTouchHandlerRegion(testPoint, renderSurfaceLayerList);
EXPECT_FALSE(resultLayer);
}
TEST(LayerTreeHostCommonTest, verifyHitCheckingTouchHandlerRegionsForSinglePositionedLayer)
{
scoped_ptr<LayerImpl> root = LayerImpl::create(12345);
WebTransformationMatrix identityMatrix;
Region touchHandlerRegion(gfx::Rect(10, 10, 50, 50));
gfx::PointF anchor(0, 0);
gfx::PointF position(50, 50); // this layer is positioned, and hit testing should correctly know where the layer is located.
gfx::Size bounds(100, 100);
setLayerPropertiesForTesting(root.get(), identityMatrix, identityMatrix, anchor, position, bounds, false);
root->setDrawsContent(true);
root->setTouchEventHandlerRegion(touchHandlerRegion);
std::vector<LayerImpl*> renderSurfaceLayerList;
int dummyMaxTextureSize = 512;
LayerTreeHostCommon::calculateDrawTransforms(root.get(), root->bounds(), 1, 1, 0, dummyMaxTextureSize, renderSurfaceLayerList);
// Sanity check the scenario we just created.
ASSERT_EQ(1u, renderSurfaceLayerList.size());
ASSERT_EQ(1u, root->renderSurface()->layerList().size());
// Hit checking for a point outside the layer should return a null pointer.
gfx::Point testPoint(49, 49);
LayerImpl* resultLayer = LayerTreeHostCommon::findLayerThatIsHitByPointInTouchHandlerRegion(testPoint, renderSurfaceLayerList);
EXPECT_FALSE(resultLayer);
// Even though the layer has a touch handler region containing (101, 101), it should not be visible there since the root renderSurface would clamp it.
testPoint = gfx::Point(101, 101);
resultLayer = LayerTreeHostCommon::findLayerThatIsHitByPointInTouchHandlerRegion(testPoint, renderSurfaceLayerList);
EXPECT_FALSE(resultLayer);
// Hit checking for a point inside the layer, but outside the touch handler region should return a null pointer.
testPoint = gfx::Point(51, 51);
resultLayer = LayerTreeHostCommon::findLayerThatIsHitByPointInTouchHandlerRegion(testPoint, renderSurfaceLayerList);
EXPECT_FALSE(resultLayer);
// Hit checking for a point inside the touch event handler region should return the root layer.
testPoint = gfx::Point(61, 61);
resultLayer = LayerTreeHostCommon::findLayerThatIsHitByPointInTouchHandlerRegion(testPoint, renderSurfaceLayerList);
ASSERT_TRUE(resultLayer);
EXPECT_EQ(12345, resultLayer->id());
testPoint = gfx::Point(99, 99);
resultLayer = LayerTreeHostCommon::findLayerThatIsHitByPointInTouchHandlerRegion(testPoint, renderSurfaceLayerList);
ASSERT_TRUE(resultLayer);
EXPECT_EQ(12345, resultLayer->id());
}
TEST(LayerTreeHostCommonTest, verifyHitCheckingTouchHandlerRegionsForSingleLayerWithScaledContents)
{
// A layer's visibleContentRect is actually in the layer's content space. The
// screenSpaceTransform converts from the layer's origin space to screen space. This
// test makes sure that hit testing works correctly accounts for the contents scale.
// A contentsScale that is not 1 effectively forces a non-identity transform between
// layer's content space and layer's origin space. The hit testing code must take this into account.
//
// To test this, the layer is positioned at (25, 25), and is size (50, 50). If
// contentsScale is ignored, then hit checking will mis-interpret the visibleContentRect
// as being larger than the actual bounds of the layer.
//
scoped_ptr<LayerImpl> root = LayerImpl::create(1);
WebTransformationMatrix identityMatrix;
gfx::PointF anchor(0, 0);
setLayerPropertiesForTesting(root.get(), identityMatrix, identityMatrix, anchor, gfx::PointF(0, 0), gfx::Size(100, 100), false);
{
Region touchHandlerRegion(gfx::Rect(10, 10, 30, 30));
gfx::PointF position(25, 25);
gfx::Size bounds(50, 50);
scoped_ptr<LayerImpl> testLayer = LayerImpl::create(12345);
setLayerPropertiesForTesting(testLayer.get(), identityMatrix, identityMatrix, anchor, position, bounds, false);
// override contentBounds and contentsScale
testLayer->setContentBounds(gfx::Size(100, 100));
testLayer->setContentsScale(2, 2);
testLayer->setDrawsContent(true);
testLayer->setTouchEventHandlerRegion(touchHandlerRegion);
root->addChild(testLayer.Pass());
}
std::vector<LayerImpl*> renderSurfaceLayerList;
int dummyMaxTextureSize = 512;
LayerTreeHostCommon::calculateDrawTransforms(root.get(), root->bounds(), 1, 1, 0, dummyMaxTextureSize, renderSurfaceLayerList);
// Sanity check the scenario we just created.
// The visibleContentRect for testLayer is actually 100x100, even though its layout size is 50x50, positioned at 25x25.
LayerImpl* testLayer = root->children()[0];
EXPECT_RECT_EQ(gfx::Rect(gfx::Point(), gfx::Size(100, 100)), testLayer->visibleContentRect());
ASSERT_EQ(1u, renderSurfaceLayerList.size());
ASSERT_EQ(1u, root->renderSurface()->layerList().size());
// 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).
gfx::Point testPoint(76, 76);
LayerImpl* resultLayer = LayerTreeHostCommon::findLayerThatIsHitByPointInTouchHandlerRegion(testPoint, renderSurfaceLayerList);
EXPECT_FALSE(resultLayer);
// Hit checking for a point inside the layer, but outside the touch handler region should return a null pointer.
testPoint = gfx::Point(26, 26);
resultLayer = LayerTreeHostCommon::findLayerThatIsHitByPointInTouchHandlerRegion(testPoint, renderSurfaceLayerList);
EXPECT_FALSE(resultLayer);
testPoint = gfx::Point(34, 34);
resultLayer = LayerTreeHostCommon::findLayerThatIsHitByPointInTouchHandlerRegion(testPoint, renderSurfaceLayerList);
EXPECT_FALSE(resultLayer);
testPoint = gfx::Point(65, 65);
resultLayer = LayerTreeHostCommon::findLayerThatIsHitByPointInTouchHandlerRegion(testPoint, renderSurfaceLayerList);
EXPECT_FALSE(resultLayer);
testPoint = gfx::Point(74, 74);
resultLayer = LayerTreeHostCommon::findLayerThatIsHitByPointInTouchHandlerRegion(testPoint, renderSurfaceLayerList);
EXPECT_FALSE(resultLayer);
// Hit checking for a point inside the touch event handler region should return the root layer.
testPoint = gfx::Point(35, 35);
resultLayer = LayerTreeHostCommon::findLayerThatIsHitByPointInTouchHandlerRegion(testPoint, renderSurfaceLayerList);
ASSERT_TRUE(resultLayer);
EXPECT_EQ(12345, resultLayer->id());
testPoint = gfx::Point(64, 64);
resultLayer = LayerTreeHostCommon::findLayerThatIsHitByPointInTouchHandlerRegion(testPoint, renderSurfaceLayerList);
ASSERT_TRUE(resultLayer);
EXPECT_EQ(12345, resultLayer->id());
}
TEST(LayerTreeHostCommonTest, verifyHitCheckingTouchHandlerRegionsForSingleLayerWithDeviceScale)
{
// The layer's deviceScalefactor and pageScaleFactor should scale the contentRect and we should
// be able to hit the touch handler region by scaling the points accordingly.
scoped_ptr<LayerImpl> root = LayerImpl::create(1);
WebTransformationMatrix identityMatrix;
gfx::PointF anchor(0, 0);
// Set the bounds of the root layer big enough to fit the child when scaled.
setLayerPropertiesForTesting(root.get(), identityMatrix, identityMatrix, anchor, gfx::PointF(0, 0), gfx::Size(100, 100), false);
{
Region touchHandlerRegion(gfx::Rect(10, 10, 30, 30));
gfx::PointF position(25, 25);
gfx::Size bounds(50, 50);
scoped_ptr<LayerImpl> testLayer = LayerImpl::create(12345);
setLayerPropertiesForTesting(testLayer.get(), identityMatrix, identityMatrix, anchor, position, bounds, false);
testLayer->setDrawsContent(true);
testLayer->setTouchEventHandlerRegion(touchHandlerRegion);
root->addChild(testLayer.Pass());
}
std::vector<LayerImpl*> renderSurfaceLayerList;
int dummyMaxTextureSize = 512;
float deviceScaleFactor = 3.0f;
float pageScaleFactor = 5.0f;
WebTransformationMatrix pageScaleTransform;
pageScaleTransform.scale(pageScaleFactor);
root->setImplTransform(pageScaleTransform); // Applying the pageScaleFactor through implTransform.
gfx::Size scaledBoundsForRoot = gfx::ToCeiledSize(gfx::ScaleSize(root->bounds(), deviceScaleFactor * pageScaleFactor));
LayerTreeHostCommon::calculateDrawTransforms(root.get(), scaledBoundsForRoot, deviceScaleFactor, 1, 0, dummyMaxTextureSize, renderSurfaceLayerList);
// Sanity check the scenario we just created.
// The visibleContentRect for testLayer is actually 100x100, even though its layout size is 50x50, positioned at 25x25.
LayerImpl* testLayer = root->children()[0];
ASSERT_EQ(1u, renderSurfaceLayerList.size());
ASSERT_EQ(1u, root->renderSurface()->layerList().size());
// Check whether the child layer fits into the root after scaled.
EXPECT_RECT_EQ(gfx::Rect(testLayer->contentBounds()), testLayer->visibleContentRect());;
// 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).
gfx::PointF testPoint(76, 76);
testPoint = gfx::ScalePoint(testPoint, deviceScaleFactor * pageScaleFactor);
LayerImpl* resultLayer = LayerTreeHostCommon::findLayerThatIsHitByPointInTouchHandlerRegion(testPoint, renderSurfaceLayerList);
EXPECT_FALSE(resultLayer);
// Hit checking for a point inside the layer, but outside the touch handler region should return a null pointer.
testPoint = gfx::Point(26, 26);
testPoint = gfx::ScalePoint(testPoint, deviceScaleFactor * pageScaleFactor);
resultLayer = LayerTreeHostCommon::findLayerThatIsHitByPointInTouchHandlerRegion(testPoint, renderSurfaceLayerList);
EXPECT_FALSE(resultLayer);
testPoint = gfx::Point(34, 34);
testPoint = gfx::ScalePoint(testPoint, deviceScaleFactor * pageScaleFactor);
resultLayer = LayerTreeHostCommon::findLayerThatIsHitByPointInTouchHandlerRegion(testPoint, renderSurfaceLayerList);
EXPECT_FALSE(resultLayer);
testPoint = gfx::Point(65, 65);
testPoint = gfx::ScalePoint(testPoint, deviceScaleFactor * pageScaleFactor);
resultLayer = LayerTreeHostCommon::findLayerThatIsHitByPointInTouchHandlerRegion(testPoint, renderSurfaceLayerList);
EXPECT_FALSE(resultLayer);
testPoint = gfx::Point(74, 74);
testPoint = gfx::ScalePoint(testPoint, deviceScaleFactor * pageScaleFactor);
resultLayer = LayerTreeHostCommon::findLayerThatIsHitByPointInTouchHandlerRegion(testPoint, renderSurfaceLayerList);
EXPECT_FALSE(resultLayer);
// Hit checking for a point inside the touch event handler region should return the root layer.
testPoint = gfx::Point(35, 35);
testPoint = gfx::ScalePoint(testPoint, deviceScaleFactor * pageScaleFactor);
resultLayer = LayerTreeHostCommon::findLayerThatIsHitByPointInTouchHandlerRegion(testPoint, renderSurfaceLayerList);
ASSERT_TRUE(resultLayer);
EXPECT_EQ(12345, resultLayer->id());
testPoint = gfx::Point(64, 64);
testPoint = gfx::ScalePoint(testPoint, deviceScaleFactor * pageScaleFactor);
resultLayer = LayerTreeHostCommon::findLayerThatIsHitByPointInTouchHandlerRegion(testPoint, renderSurfaceLayerList);
ASSERT_TRUE(resultLayer);
EXPECT_EQ(12345, resultLayer->id());
}
TEST(LayerTreeHostCommonTest, verifyHitCheckingTouchHandlerRegionsForSimpleClippedLayer)
{
// Test that hit-checking will only work for the visible portion of a layer, and not
// the entire layer bounds. Here we just test the simple axis-aligned case.
WebTransformationMatrix identityMatrix;
gfx::PointF anchor(0, 0);
scoped_ptr<LayerImpl> root = LayerImpl::create(1);
setLayerPropertiesForTesting(root.get(), identityMatrix, identityMatrix, anchor, gfx::PointF(0, 0), gfx::Size(100, 100), false);
{
scoped_ptr<LayerImpl> clippingLayer = LayerImpl::create(123);
gfx::PointF position(25, 25); // this layer is positioned, and hit testing should correctly know where the layer is located.
gfx::Size bounds(50, 50);
setLayerPropertiesForTesting(clippingLayer.get(), identityMatrix, identityMatrix, anchor, position, bounds, false);
clippingLayer->setMasksToBounds(true);
scoped_ptr<LayerImpl> child = LayerImpl::create(456);
Region touchHandlerRegion(gfx::Rect(10, 10, 50, 50));
position = gfx::PointF(-50, -50);
bounds = gfx::Size(300, 300);
setLayerPropertiesForTesting(child.get(), identityMatrix, identityMatrix, anchor, position, bounds, false);
child->setDrawsContent(true);
child->setTouchEventHandlerRegion(touchHandlerRegion);
clippingLayer->addChild(child.Pass());
root->addChild(clippingLayer.Pass());
}
std::vector<LayerImpl*> renderSurfaceLayerList;
int dummyMaxTextureSize = 512;
LayerTreeHostCommon::calculateDrawTransforms(root.get(), root->bounds(), 1, 1, 0, dummyMaxTextureSize, renderSurfaceLayerList);
// Sanity check the scenario we just created.
ASSERT_EQ(1u, renderSurfaceLayerList.size());
ASSERT_EQ(1u, root->renderSurface()->layerList().size());
ASSERT_EQ(456, root->renderSurface()->layerList()[0]->id());
// Hit checking for a point outside the layer should return a null pointer.
// Despite the child layer being very large, it should be clipped to the root layer's bounds.
gfx::Point testPoint(24, 24);
LayerImpl* resultLayer = LayerTreeHostCommon::findLayerThatIsHitByPointInTouchHandlerRegion(testPoint, renderSurfaceLayerList);
EXPECT_FALSE(resultLayer);
// Hit checking for a point inside the layer, but outside the touch handler region should return a null pointer.
testPoint = gfx::Point(35, 35);
resultLayer = LayerTreeHostCommon::findLayerThatIsHitByPointInTouchHandlerRegion(testPoint, renderSurfaceLayerList);
EXPECT_FALSE(resultLayer);
testPoint = gfx::Point(74, 74);
resultLayer = LayerTreeHostCommon::findLayerThatIsHitByPointInTouchHandlerRegion(testPoint, renderSurfaceLayerList);
EXPECT_FALSE(resultLayer);
// Hit checking for a point inside the touch event handler region should return the root layer.
testPoint = gfx::Point(25, 25);
resultLayer = LayerTreeHostCommon::findLayerThatIsHitByPointInTouchHandlerRegion(testPoint, renderSurfaceLayerList);
ASSERT_TRUE(resultLayer);
EXPECT_EQ(456, resultLayer->id());
testPoint = gfx::Point(34, 34);
resultLayer = LayerTreeHostCommon::findLayerThatIsHitByPointInTouchHandlerRegion(testPoint, renderSurfaceLayerList);
ASSERT_TRUE(resultLayer);
EXPECT_EQ(456, resultLayer->id());
}
class NoScaleContentLayer : public ContentLayer
{
public:

@ -324,6 +324,21 @@ void LayerTreeHostImpl::scheduleAnimation()
m_client->setNeedsRedrawOnImplThread();
}
bool LayerTreeHostImpl::haveTouchEventHandlersAt(const gfx::Point& viewportPoint)
{
gfx::PointF deviceViewportPoint = gfx::ScalePoint(viewportPoint, m_deviceScaleFactor);
// First find out which layer was hit from the saved list of visible layers
// in the most recent frame.
LayerImpl* layerImplHitByPointInTouchHandlerRegion = LayerTreeHostCommon::findLayerThatIsHitByPointInTouchHandlerRegion(deviceViewportPoint, m_renderSurfaceLayerList);
if (layerImplHitByPointInTouchHandlerRegion)
return true;
return false;
}
void LayerTreeHostImpl::trackDamageForAllSurfaces(LayerImpl* rootDrawLayer, const LayerList& renderSurfaceLayerList)
{
// For now, we use damage tracking to compute a global scissor. To do this, we must

@ -125,6 +125,7 @@ public:
virtual void pinchGestureEnd() OVERRIDE;
virtual void startPageScaleAnimation(gfx::Vector2d targetOffset, bool anchorPoint, float pageScale, base::TimeTicks startTime, base::TimeDelta duration) OVERRIDE;
virtual void scheduleAnimation() OVERRIDE;
virtual bool haveTouchEventHandlersAt(const gfx::Point&) OVERRIDE;
struct CC_EXPORT FrameData : public RenderPassSink {
FrameData();

@ -93,6 +93,11 @@ public:
m_client->scheduleAnimation();
}
virtual bool haveTouchEventHandlersAt(WebPoint point)
{
return m_client->haveTouchEventHandlersAt(point);
}
private:
cc::InputHandlerClient* m_client;
};