зеркало из https://github.com/mozilla/gecko-dev.git
Bug 890280 - Apply proper transformations when sending inputs to the APZC and back to the DOM. r=BenWa
This commit is contained in:
Родитель
571e6a0e9c
Коммит
9dd2faacc5
|
@ -87,9 +87,6 @@ APZCTreeManager::UpdatePanZoomControllerTree(CompositorParent* aCompositor,
|
|||
bool aIsFirstPaint, uint64_t aFirstPaintLayersId,
|
||||
nsTArray< nsRefPtr<AsyncPanZoomController> >* aApzcsToDestroy)
|
||||
{
|
||||
// Accumulate the CSS transform between layers that have an APZC
|
||||
aTransform = aTransform * aLayer->GetTransform();
|
||||
|
||||
ContainerLayer* container = aLayer->AsContainerLayer();
|
||||
AsyncPanZoomController* controller = nullptr;
|
||||
if (container) {
|
||||
|
@ -121,9 +118,7 @@ APZCTreeManager::UpdatePanZoomControllerTree(CompositorParent* aCompositor,
|
|||
aIsFirstPaint && (aLayersId == aFirstPaintLayersId));
|
||||
|
||||
LayerRect visible = container->GetFrameMetrics().mViewport * container->GetFrameMetrics().LayersPixelsPerCSSPixel();
|
||||
controller->SetLayerHitTestData(visible, aTransform);
|
||||
// Reset the accumulated transform once we hit a layer with an APZC
|
||||
aTransform = gfx3DMatrix();
|
||||
controller->SetLayerHitTestData(visible, aTransform, aLayer->GetTransform());
|
||||
APZC_LOG("Setting rect(%f %f %f %f) as visible region for APZC %p\n", visible.x, visible.y,
|
||||
visible.width, visible.height,
|
||||
controller);
|
||||
|
@ -145,6 +140,15 @@ APZCTreeManager::UpdatePanZoomControllerTree(CompositorParent* aCompositor,
|
|||
container->SetAsyncPanZoomController(controller);
|
||||
}
|
||||
|
||||
// Accumulate the CSS transform between layers that have an APZC, but exclude any
|
||||
// any layers that do have an APZC, and reset the accumulation at those layers.
|
||||
if (controller) {
|
||||
aTransform = gfx3DMatrix();
|
||||
} else {
|
||||
// Multiply child layer transforms on the left so they get applied first
|
||||
aTransform = aLayer->GetTransform() * aTransform;
|
||||
}
|
||||
|
||||
uint64_t childLayersId = (aLayer->AsRefLayer() ? aLayer->AsRefLayer()->GetReferentId() : aLayersId);
|
||||
AsyncPanZoomController* next = nullptr;
|
||||
for (Layer* child = aLayer->GetLastChild(); child; child = child->GetPrevSibling()) {
|
||||
|
@ -165,31 +169,69 @@ APZCTreeManager::UpdatePanZoomControllerTree(CompositorParent* aCompositor,
|
|||
return aNextSibling;
|
||||
}
|
||||
|
||||
/*static*/ template<class T> void
|
||||
ApplyTransform(gfx::PointTyped<T>* aPoint, const gfx3DMatrix& aMatrix)
|
||||
{
|
||||
gfxPoint result = aMatrix.Transform(gfxPoint(aPoint->x, aPoint->y));
|
||||
aPoint->x = result.x;
|
||||
aPoint->y = result.y;
|
||||
}
|
||||
|
||||
/*static*/ template<class T> void
|
||||
ApplyTransform(gfx::IntPointTyped<T>* aPoint, const gfx3DMatrix& aMatrix)
|
||||
{
|
||||
gfxPoint result = aMatrix.Transform(gfxPoint(aPoint->x, aPoint->y));
|
||||
aPoint->x = NS_lround(result.x);
|
||||
aPoint->y = NS_lround(result.y);
|
||||
}
|
||||
|
||||
/*static*/ void
|
||||
ApplyTransform(nsIntPoint* aPoint, const gfx3DMatrix& aMatrix)
|
||||
{
|
||||
gfxPoint result = aMatrix.Transform(gfxPoint(aPoint->x, aPoint->y));
|
||||
aPoint->x = NS_lround(result.x);
|
||||
aPoint->y = NS_lround(result.y);
|
||||
}
|
||||
|
||||
nsEventStatus
|
||||
APZCTreeManager::ReceiveInputEvent(const InputData& aEvent)
|
||||
{
|
||||
nsRefPtr<AsyncPanZoomController> apzc;
|
||||
gfx3DMatrix transformToApzc;
|
||||
gfx3DMatrix transformToScreen;
|
||||
switch (aEvent.mInputType) {
|
||||
case MULTITOUCH_INPUT: {
|
||||
const MultiTouchInput& multiTouchInput = aEvent.AsMultiTouchInput();
|
||||
apzc = GetTargetAPZC(ScreenPoint(multiTouchInput.mTouches[0].mScreenPoint));
|
||||
apzc = GetTargetAPZC(ScreenPoint(multiTouchInput.mTouches[0].mScreenPoint),
|
||||
transformToApzc, transformToScreen);
|
||||
if (apzc) {
|
||||
MultiTouchInput inputForApzc(multiTouchInput);
|
||||
for (int i = inputForApzc.mTouches.Length() - 1; i >= 0; i--) {
|
||||
ApplyTransform(&(inputForApzc.mTouches[i].mScreenPoint), transformToApzc);
|
||||
}
|
||||
apzc->ReceiveInputEvent(inputForApzc);
|
||||
}
|
||||
break;
|
||||
} case PINCHGESTURE_INPUT: {
|
||||
const PinchGestureInput& pinchInput = aEvent.AsPinchGestureInput();
|
||||
apzc = GetTargetAPZC(pinchInput.mFocusPoint);
|
||||
apzc = GetTargetAPZC(pinchInput.mFocusPoint, transformToApzc, transformToScreen);
|
||||
if (apzc) {
|
||||
PinchGestureInput inputForApzc(pinchInput);
|
||||
ApplyTransform(&(inputForApzc.mFocusPoint), transformToApzc);
|
||||
apzc->ReceiveInputEvent(inputForApzc);
|
||||
}
|
||||
break;
|
||||
} case TAPGESTURE_INPUT: {
|
||||
const TapGestureInput& tapInput = aEvent.AsTapGestureInput();
|
||||
apzc = GetTargetAPZC(ScreenPoint(tapInput.mPoint));
|
||||
break;
|
||||
} default: {
|
||||
// leave apzc as nullptr
|
||||
apzc = GetTargetAPZC(ScreenPoint(tapInput.mPoint), transformToApzc, transformToScreen);
|
||||
if (apzc) {
|
||||
TapGestureInput inputForApzc(tapInput);
|
||||
ApplyTransform(&(inputForApzc.mPoint), transformToApzc);
|
||||
apzc->ReceiveInputEvent(inputForApzc);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (apzc) {
|
||||
return apzc->ReceiveInputEvent(aEvent);
|
||||
}
|
||||
return nsEventStatus_eIgnore;
|
||||
}
|
||||
|
||||
|
@ -200,27 +242,51 @@ APZCTreeManager::ReceiveInputEvent(const nsInputEvent& aEvent,
|
|||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
nsRefPtr<AsyncPanZoomController> apzc;
|
||||
gfx3DMatrix transformToApzc;
|
||||
gfx3DMatrix transformToScreen;
|
||||
switch (aEvent.eventStructType) {
|
||||
case NS_TOUCH_EVENT: {
|
||||
const nsTouchEvent& touchEvent = static_cast<const nsTouchEvent&>(aEvent);
|
||||
if (touchEvent.touches.Length() > 0) {
|
||||
nsIntPoint point = touchEvent.touches[0]->mRefPoint;
|
||||
apzc = GetTargetAPZC(ScreenPoint::FromUnknownPoint(gfx::Point(point.x, point.y)));
|
||||
apzc = GetTargetAPZC(ScreenPoint::FromUnknownPoint(gfx::Point(point.x, point.y)),
|
||||
transformToApzc, transformToScreen);
|
||||
if (apzc) {
|
||||
MultiTouchInput inputForApzc(touchEvent);
|
||||
for (int i = inputForApzc.mTouches.Length() - 1; i >= 0; i--) {
|
||||
ApplyTransform(&(inputForApzc.mTouches[i].mScreenPoint), transformToApzc);
|
||||
}
|
||||
|
||||
gfx3DMatrix outTransform = transformToApzc * transformToScreen;
|
||||
nsTouchEvent* outEvent = static_cast<nsTouchEvent*>(aOutEvent);
|
||||
for (int i = outEvent->touches.Length() - 1; i >= 0; i--) {
|
||||
ApplyTransform(&(outEvent->touches[i]->mRefPoint), outTransform);
|
||||
}
|
||||
|
||||
return apzc->ReceiveInputEvent(inputForApzc);
|
||||
}
|
||||
}
|
||||
break;
|
||||
} case NS_MOUSE_EVENT: {
|
||||
const nsMouseEvent& mouseEvent = static_cast<const nsMouseEvent&>(aEvent);
|
||||
apzc = GetTargetAPZC(ScreenPoint::FromUnknownPoint(gfx::Point(mouseEvent.refPoint.x,
|
||||
mouseEvent.refPoint.y)));
|
||||
mouseEvent.refPoint.y)),
|
||||
transformToApzc, transformToScreen);
|
||||
if (apzc) {
|
||||
MultiTouchInput inputForApzc(mouseEvent);
|
||||
ApplyTransform(&(inputForApzc.mTouches[0].mScreenPoint), transformToApzc);
|
||||
|
||||
gfx3DMatrix outTransform = transformToApzc * transformToScreen;
|
||||
ApplyTransform(&(static_cast<nsMouseEvent*>(aOutEvent)->refPoint), outTransform);
|
||||
|
||||
return apzc->ReceiveInputEvent(inputForApzc);
|
||||
}
|
||||
break;
|
||||
} default: {
|
||||
// leave apzc as nullptr
|
||||
// Ignore other event types
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (apzc) {
|
||||
return apzc->ReceiveInputEvent(aEvent, aOutEvent);
|
||||
}
|
||||
return nsEventStatus_eIgnore;
|
||||
}
|
||||
|
||||
|
@ -334,15 +400,84 @@ APZCTreeManager::GetTargetAPZC(const ScrollableLayerGuid& aGuid)
|
|||
return target.forget();
|
||||
}
|
||||
|
||||
/* This function returns the AsyncPanZoomController instance that hit testing determines
|
||||
is under the given ScreenPoint.
|
||||
|
||||
In addition, the aTransformToApzcOut and aTransformToScreenOut out-parameters are filled
|
||||
with some useful transformations that input events may need applied. This is best
|
||||
illustrated with an example. Consider a chain of layers, L, M, N, O, P, Q, R. Layer L
|
||||
is the layer that corresponds to the returned APZC instance, and layer R is the root
|
||||
of the layer tree. Layer M is the parent of L, N is the parent of M, and so on.
|
||||
When layer L is displayed to the screen by the compositor, the set of transforms that
|
||||
are applied to L are (in order from top to bottom):
|
||||
|
||||
L's CSS transform (hereafter referred to as transform matrix LC)
|
||||
L's async transform (hereafter referred to as transform matrix LA)
|
||||
M's CSS transform (hereafter referred to as transform matrix MC)
|
||||
M's async transform (hereafter referred to as transform matrix MA)
|
||||
...
|
||||
R's CSS transform (hereafter referred to as transform matrix RC)
|
||||
R's async transform (hereafter referred to as transform matrix RA)
|
||||
|
||||
Therefore, if we want user input to modify L's async transform, we have to first convert
|
||||
user input from screen space to the coordinate space of L's async transform. Doing this
|
||||
involves applying the following transforms (in order from top to bottom):
|
||||
RA.Inverse()
|
||||
RC.Inverse()
|
||||
...
|
||||
MA.Inverse()
|
||||
MC.Inverse()
|
||||
This combined transformation is returned in the aTransformToApzcOut out-parameter.
|
||||
|
||||
Next, if we want user inputs sent to gecko for event-dispatching, we will need to strip
|
||||
out all of the async transforms that are involved in this chain. This is because async
|
||||
transforms are stored only in the compositor and gecko does not account for them when
|
||||
doing display-list-based hit-testing for event dispatching. Therefore, given a user input
|
||||
in screen space, the following transforms need to be applied (in order from top to bottom):
|
||||
RA.Inverse()
|
||||
RC.Inverse()
|
||||
...
|
||||
MA.Inverse()
|
||||
MC.Inverse()
|
||||
LA.Inverse()
|
||||
LC.Inverse()
|
||||
LC
|
||||
MC
|
||||
...
|
||||
RC
|
||||
This sequence can be simplified and refactored to the following:
|
||||
aTransformToApzcOut
|
||||
LA.Inverse()
|
||||
MC
|
||||
...
|
||||
RC
|
||||
Since aTransformToApzcOut is already one of the out-parameters, we set aTransformToScreenOut
|
||||
to the remaining transforms (LA.Inverse() * MC * ... * RC), so that the caller code can
|
||||
combine it with aTransformToApzcOut to get the final transform required in this case.
|
||||
|
||||
Note that for many of these layers, there will be no AsyncPanZoomController attached, and
|
||||
so the async transform will be the identity transform. So, in the example above, if layers
|
||||
L and P have APZC instances attached, MA, NA, OA, QA, and RA will be identity transforms.
|
||||
Additionally, for space-saving purposes, each APZC instance stores its layers individual
|
||||
CSS transform and the accumulation of CSS transforms to its parent APZC. So the APZC for
|
||||
layer L would store LC and (MC * NC * OC), and the layer P would store PC and (QC * RC).
|
||||
The APZCs also obviously have LA and PA, so all of the above transformation combinations
|
||||
required can be generated.
|
||||
|
||||
Note that this function may return null, in which case the matrix out-parameters are
|
||||
left unmodified.
|
||||
*/
|
||||
already_AddRefed<AsyncPanZoomController>
|
||||
APZCTreeManager::GetTargetAPZC(const ScreenPoint& aPoint)
|
||||
APZCTreeManager::GetTargetAPZC(const ScreenPoint& aPoint,
|
||||
gfx3DMatrix& aTransformToApzcOut,
|
||||
gfx3DMatrix& aTransformToScreenOut)
|
||||
{
|
||||
MonitorAutoLock lock(mTreeLock);
|
||||
nsRefPtr<AsyncPanZoomController> target;
|
||||
// The root may have siblings, so check those too
|
||||
gfxPoint point(aPoint.x, aPoint.y);
|
||||
for (AsyncPanZoomController* apzc = mRootApzc; apzc; apzc = apzc->GetPrevSibling()) {
|
||||
target = GetAPZCAtPoint(apzc, point);
|
||||
target = GetAPZCAtPoint(apzc, point, aTransformToApzcOut, aTransformToScreenOut);
|
||||
if (target) {
|
||||
break;
|
||||
}
|
||||
|
@ -368,23 +503,52 @@ APZCTreeManager::FindTargetAPZC(AsyncPanZoomController* aApzc, const ScrollableL
|
|||
}
|
||||
|
||||
AsyncPanZoomController*
|
||||
APZCTreeManager::GetAPZCAtPoint(AsyncPanZoomController* aApzc, gfxPoint aHitTestPoint)
|
||||
APZCTreeManager::GetAPZCAtPoint(AsyncPanZoomController* aApzc, const gfxPoint& aHitTestPoint,
|
||||
gfx3DMatrix& aTransformToApzcOut, gfx3DMatrix& aTransformToScreenOut)
|
||||
{
|
||||
gfx3DMatrix transform = gfx3DMatrix(aApzc->GetCurrentAsyncTransform()) * aApzc->GetCSSTransform();
|
||||
gfx3DMatrix untransform = transform.Inverse();
|
||||
gfxPoint untransformed = untransform.ProjectPoint(aHitTestPoint);
|
||||
// The comments below assume there is a chain of layers L..R with L and P having APZC instances as
|
||||
// explained in the comment on GetTargetAPZC. This function will recurse with aApzc at L and P, and the
|
||||
// comments explain what values are stored in the variables at these two levels. All the comments
|
||||
// use standard matrix notation where the leftmost matrix in a multiplication is applied first.
|
||||
|
||||
// ancestorUntransform is OC.Inverse() * NC.Inverse() * MC.Inverse() at recursion level for L,
|
||||
// and RC.Inverse() * QC.Inverse() at recursion level for P.
|
||||
gfx3DMatrix ancestorUntransform = aApzc->GetAncestorTransform().Inverse();
|
||||
// asyncUntransform is LA.Inverse() at recursion level for L,
|
||||
// and PA.Inverse() at recursion level for P.
|
||||
gfx3DMatrix asyncUntransform = gfx3DMatrix(aApzc->GetCurrentAsyncTransform()).Inverse();
|
||||
// untransformSinceLastApzc is OC.Inverse() * NC.Inverse() * MC.Inverse() * LA.Inverse() * LC.Inverse() at L,
|
||||
// and RC.Inverse() * QC.Inverse() * PA.Inverse() * PC.Inverse() at P.
|
||||
gfx3DMatrix untransformSinceLastApzc = ancestorUntransform * asyncUntransform * aApzc->GetCSSTransform().Inverse();
|
||||
// untransformed is the user input in L's layer space at L,
|
||||
// and in P's layer space at P.
|
||||
gfxPoint untransformed = untransformSinceLastApzc.ProjectPoint(aHitTestPoint);
|
||||
APZC_LOG("Untransformed %f %f to %f %f for APZC %p\n", aHitTestPoint.x, aHitTestPoint.y, untransformed.x, untransformed.y, aApzc);
|
||||
|
||||
// This walks the tree in depth-first, reverse order, so that it encounters
|
||||
// APZCs front-to-back on the screen.
|
||||
for (AsyncPanZoomController* child = aApzc->GetLastChild(); child; child = child->GetPrevSibling()) {
|
||||
AsyncPanZoomController* match = GetAPZCAtPoint(child, untransformed);
|
||||
AsyncPanZoomController* match = GetAPZCAtPoint(child, untransformed, aTransformToApzcOut, aTransformToScreenOut);
|
||||
if (match) {
|
||||
// This code is not run in the recursion at layer L.
|
||||
// aTransformToApzcOut is RC.Inverse() * QC.Inverse() * PA.Inverse() * PC.Inverse() * OC.Inverse() * NC.Inverse() * MC.Inverse()
|
||||
// at recursion level for P
|
||||
aTransformToApzcOut = untransformSinceLastApzc * aTransformToApzcOut;
|
||||
// aTransformToScreenOut is LA.Inverse() * MC * NC * OC * PC * QC * RC at recursion level for P
|
||||
aTransformToScreenOut = aTransformToScreenOut * aApzc->GetCSSTransform() * aApzc->GetAncestorTransform();
|
||||
// The above values for aTransformToApzcOut and aTransformToScreenOut at recursion level for P match
|
||||
// the required output as explained in the comment above GetTargetAPZC. Note that any missing terms
|
||||
// are async transforms that are guaranteed to be identity transforms.
|
||||
return match;
|
||||
}
|
||||
}
|
||||
if (aApzc->VisibleRegionContains(LayerPoint(untransformed.x, untransformed.y))) {
|
||||
APZC_LOG("Successfully matched untransformed point %f %f to visible region for APZC %p\n", untransformed.x, untransformed.y, aApzc);
|
||||
// This code is not run in the recursion at layer P.
|
||||
// aTransformToApzcOut is OC.Inverse() * NC.Inverse() * MC.Inverse() at recursion level for L.
|
||||
aTransformToApzcOut = ancestorUntransform;
|
||||
// aTransformToScreenOut is LA.Inverse() * MC * NC * OC at recursion level for L.
|
||||
aTransformToScreenOut = asyncUntransform * aApzc->GetAncestorTransform();
|
||||
return aApzc;
|
||||
}
|
||||
return nullptr;
|
||||
|
|
|
@ -236,11 +236,13 @@ public:
|
|||
used by other production code.
|
||||
*/
|
||||
already_AddRefed<AsyncPanZoomController> GetTargetAPZC(const ScrollableLayerGuid& aGuid);
|
||||
already_AddRefed<AsyncPanZoomController> GetTargetAPZC(const ScreenPoint& aPoint);
|
||||
already_AddRefed<AsyncPanZoomController> GetTargetAPZC(const ScreenPoint& aPoint, gfx3DMatrix& aTransformToApzcOut,
|
||||
gfx3DMatrix& aTransformToScreenOut);
|
||||
private:
|
||||
/* Recursive helpers */
|
||||
AsyncPanZoomController* FindTargetAPZC(AsyncPanZoomController* aApzc, const ScrollableLayerGuid& aGuid);
|
||||
AsyncPanZoomController* GetAPZCAtPoint(AsyncPanZoomController* aApzc, gfxPoint aHitTestPoint);
|
||||
AsyncPanZoomController* GetAPZCAtPoint(AsyncPanZoomController* aApzc, const gfxPoint& aHitTestPoint,
|
||||
gfx3DMatrix& aTransformToApzcOut, gfx3DMatrix& aTransformToScreenOut);
|
||||
|
||||
/**
|
||||
* Recursive helper function to build the APZC tree. The tree of APZC instances has
|
||||
|
|
|
@ -247,64 +247,6 @@ WidgetSpaceToCompensatedViewportSpace(const ScreenPoint& aPoint,
|
|||
return aPoint / aCurrentZoom;
|
||||
}
|
||||
|
||||
nsEventStatus
|
||||
AsyncPanZoomController::ReceiveInputEvent(const nsInputEvent& aEvent,
|
||||
nsInputEvent* aOutEvent)
|
||||
{
|
||||
CSSToScreenScale currentResolution;
|
||||
{
|
||||
ReentrantMonitorAutoEnter lock(mMonitor);
|
||||
currentResolution = mFrameMetrics.CalculateResolution();
|
||||
}
|
||||
|
||||
nsEventStatus status;
|
||||
switch (aEvent.eventStructType) {
|
||||
case NS_TOUCH_EVENT: {
|
||||
MultiTouchInput event(static_cast<const nsTouchEvent&>(aEvent));
|
||||
status = ReceiveInputEvent(event);
|
||||
break;
|
||||
}
|
||||
case NS_MOUSE_EVENT: {
|
||||
MultiTouchInput event(static_cast<const nsMouseEvent&>(aEvent));
|
||||
status = ReceiveInputEvent(event);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
status = nsEventStatus_eIgnore;
|
||||
break;
|
||||
}
|
||||
|
||||
switch (aEvent.eventStructType) {
|
||||
case NS_TOUCH_EVENT: {
|
||||
nsTouchEvent* touchEvent = static_cast<nsTouchEvent*>(aOutEvent);
|
||||
const nsTArray< nsRefPtr<dom::Touch> >& touches = touchEvent->touches;
|
||||
for (uint32_t i = 0; i < touches.Length(); ++i) {
|
||||
dom::Touch* touch = touches[i];
|
||||
if (touch) {
|
||||
CSSPoint refCSSPoint = WidgetSpaceToCompensatedViewportSpace(
|
||||
ScreenPoint::FromUnknownPoint(gfx::Point(
|
||||
touch->mRefPoint.x, touch->mRefPoint.y)),
|
||||
currentResolution);
|
||||
LayoutDevicePoint refPoint = refCSSPoint * mFrameMetrics.mDevPixelsPerCSSPixel;
|
||||
touch->mRefPoint = nsIntPoint(refPoint.x, refPoint.y);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
CSSPoint refCSSPoint = WidgetSpaceToCompensatedViewportSpace(
|
||||
ScreenPoint::FromUnknownPoint(gfx::Point(
|
||||
aOutEvent->refPoint.x, aOutEvent->refPoint.y)),
|
||||
currentResolution);
|
||||
LayoutDevicePoint refPoint = refCSSPoint * mFrameMetrics.mDevPixelsPerCSSPixel;
|
||||
aOutEvent->refPoint = LayoutDeviceIntPoint(refPoint.x, refPoint.y);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
nsEventStatus AsyncPanZoomController::ReceiveInputEvent(const InputData& aEvent) {
|
||||
// If we may have touch listeners, we enable the machinery that allows touch
|
||||
// listeners to preventDefault any touch inputs. This should not happen unless
|
||||
|
|
|
@ -100,19 +100,6 @@ public:
|
|||
*/
|
||||
nsEventStatus ReceiveInputEvent(const InputData& aEvent);
|
||||
|
||||
/**
|
||||
* Special handler for nsInputEvents. Also sets |aOutEvent| (which is assumed
|
||||
* to be an already-existing instance of an nsInputEvent which may be an
|
||||
* nsTouchEvent) to have its touch points in DOM space. This is so that the
|
||||
* touches can be passed through the DOM and content can handle them.
|
||||
*
|
||||
* NOTE: Be careful of invoking the nsInputEvent variant. This can only be
|
||||
* called on the main thread. See widget/InputData.h for more information on
|
||||
* why we have InputData and nsInputEvent separated.
|
||||
*/
|
||||
nsEventStatus ReceiveInputEvent(const nsInputEvent& aEvent,
|
||||
nsInputEvent* aOutEvent);
|
||||
|
||||
/**
|
||||
* Updates the composition bounds, i.e. the dimensions of the final size of
|
||||
* the frame this is tied to during composition onto, in device pixels. In
|
||||
|
@ -642,9 +629,15 @@ private:
|
|||
* hit-testing to see which APZC instance should handle touch events.
|
||||
*/
|
||||
public:
|
||||
void SetLayerHitTestData(const LayerRect& aRect, const gfx3DMatrix& aTransform) {
|
||||
void SetLayerHitTestData(const LayerRect& aRect, const gfx3DMatrix& aTransformToLayer,
|
||||
const gfx3DMatrix& aTransformForLayer) {
|
||||
mVisibleRect = aRect;
|
||||
mCSSTransform = aTransform;
|
||||
mAncestorTransform = aTransformToLayer;
|
||||
mCSSTransform = aTransformForLayer;
|
||||
}
|
||||
|
||||
gfx3DMatrix GetAncestorTransform() const {
|
||||
return mAncestorTransform;
|
||||
}
|
||||
|
||||
gfx3DMatrix GetCSSTransform() const {
|
||||
|
@ -661,8 +654,10 @@ private:
|
|||
* applied to any layers, whether they are CSS transforms or async
|
||||
* transforms. */
|
||||
LayerRect mVisibleRect;
|
||||
/* This is the cumulative layer transform from the parent APZC down to this
|
||||
* one. */
|
||||
/* This is the cumulative CSS transform for all the layers between the parent
|
||||
* APZC and this one (not inclusive) */
|
||||
gfx3DMatrix mAncestorTransform;
|
||||
/* This is the CSS transform for this APZC's layer. */
|
||||
gfx3DMatrix mCSSTransform;
|
||||
};
|
||||
|
||||
|
|
|
@ -376,16 +376,17 @@ TEST(APZCTreeManager, GetAPZCAtPoint) {
|
|||
ScopedLayerTreeRegistration controller(0, root, mcc);
|
||||
|
||||
nsRefPtr<APZCTreeManager> manager = new TestAPZCTreeManager();
|
||||
gfx3DMatrix matrix;
|
||||
|
||||
// No APZC attached so hit testing will return no APZC at (20,20)
|
||||
nsRefPtr<AsyncPanZoomController> hit = manager->GetTargetAPZC(ScreenPoint(20, 20));
|
||||
nsRefPtr<AsyncPanZoomController> hit = manager->GetTargetAPZC(ScreenPoint(20, 20), matrix, matrix);
|
||||
AsyncPanZoomController* nullAPZC = nullptr;
|
||||
EXPECT_EQ(nullAPZC, hit.get());
|
||||
|
||||
// Now we have a root APZC that will match the page
|
||||
SetScrollableFrameMetrics(root, FrameMetrics::ROOT_SCROLL_ID, mcc);
|
||||
manager->UpdatePanZoomControllerTree(nullptr, root, 0, false);
|
||||
hit = manager->GetTargetAPZC(ScreenPoint(15, 15));
|
||||
hit = manager->GetTargetAPZC(ScreenPoint(15, 15), matrix, matrix);
|
||||
EXPECT_EQ(root->AsContainerLayer()->GetAsyncPanZoomController(), hit.get());
|
||||
// expect hit point at LayerIntPoint(15, 15)
|
||||
|
||||
|
@ -393,28 +394,28 @@ TEST(APZCTreeManager, GetAPZCAtPoint) {
|
|||
SetScrollableFrameMetrics(layers[3], FrameMetrics::START_SCROLL_ID, mcc);
|
||||
manager->UpdatePanZoomControllerTree(nullptr, root, 0, false);
|
||||
EXPECT_NE(root->AsContainerLayer()->GetAsyncPanZoomController(), layers[3]->AsContainerLayer()->GetAsyncPanZoomController());
|
||||
hit = manager->GetTargetAPZC(ScreenPoint(15, 15));
|
||||
hit = manager->GetTargetAPZC(ScreenPoint(15, 15), matrix, matrix);
|
||||
EXPECT_EQ(layers[3]->AsContainerLayer()->GetAsyncPanZoomController(), hit.get());
|
||||
// expect hit point at LayerIntPoint(15, 15)
|
||||
|
||||
// Now test hit testing when we have two scrollable layers
|
||||
hit = manager->GetTargetAPZC(ScreenPoint(15, 15));
|
||||
hit = manager->GetTargetAPZC(ScreenPoint(15, 15), matrix, matrix);
|
||||
EXPECT_EQ(layers[3]->AsContainerLayer()->GetAsyncPanZoomController(), hit.get());
|
||||
SetScrollableFrameMetrics(layers[4], FrameMetrics::START_SCROLL_ID + 1, mcc);
|
||||
manager->UpdatePanZoomControllerTree(nullptr, root, 0, false);
|
||||
hit = manager->GetTargetAPZC(ScreenPoint(15, 15));
|
||||
hit = manager->GetTargetAPZC(ScreenPoint(15, 15), matrix, matrix);
|
||||
EXPECT_EQ(layers[4]->AsContainerLayer()->GetAsyncPanZoomController(), hit.get());
|
||||
// expect hit point at LayerIntPoint(15, 15)
|
||||
|
||||
// Hit test ouside the reach of layer[3,4] but inside root
|
||||
hit = manager->GetTargetAPZC(ScreenPoint(90, 90));
|
||||
hit = manager->GetTargetAPZC(ScreenPoint(90, 90), matrix, matrix);
|
||||
EXPECT_EQ(root->AsContainerLayer()->GetAsyncPanZoomController(), hit.get());
|
||||
// expect hit point at LayerIntPoint(90, 90)
|
||||
|
||||
// Hit test ouside the reach of any layer
|
||||
hit = manager->GetTargetAPZC(ScreenPoint(1000, 10));
|
||||
hit = manager->GetTargetAPZC(ScreenPoint(1000, 10), matrix, matrix);
|
||||
EXPECT_EQ(nullAPZC, hit.get());
|
||||
hit = manager->GetTargetAPZC(ScreenPoint(-1000, 10));
|
||||
hit = manager->GetTargetAPZC(ScreenPoint(-1000, 10), matrix, matrix);
|
||||
EXPECT_EQ(nullAPZC, hit.get());
|
||||
|
||||
// Test layer transform
|
||||
|
@ -422,12 +423,12 @@ TEST(APZCTreeManager, GetAPZCAtPoint) {
|
|||
transform.ScalePost(0.1, 0.1, 1);
|
||||
root->SetBaseTransform(transform);
|
||||
manager->UpdatePanZoomControllerTree(nullptr, root, 0, false);
|
||||
hit = manager->GetTargetAPZC(ScreenPoint(50, 50)); // This point is now outside the root layer
|
||||
hit = manager->GetTargetAPZC(ScreenPoint(50, 50), matrix, matrix); // This point is now outside the root layer
|
||||
EXPECT_EQ(nullAPZC, hit.get());
|
||||
|
||||
// This hit test will hit both layers[3] and layers[4]; layers[4] is later in the tree so
|
||||
// it is a better match
|
||||
hit = manager->GetTargetAPZC(ScreenPoint(2, 2));
|
||||
hit = manager->GetTargetAPZC(ScreenPoint(2, 2), matrix, matrix);
|
||||
EXPECT_EQ(layers[4]->AsContainerLayer()->GetAsyncPanZoomController(), hit.get());
|
||||
// expect hit point at LayerPoint(20, 20)
|
||||
|
||||
|
@ -436,7 +437,7 @@ TEST(APZCTreeManager, GetAPZCAtPoint) {
|
|||
// layer 4 effective visible screenrect: (0.05, 0.05, 0.2, 0.2)
|
||||
// Does not contain (2, 2)
|
||||
manager->UpdatePanZoomControllerTree(nullptr, root, 0, false);
|
||||
hit = manager->GetTargetAPZC(ScreenPoint(2, 2));
|
||||
hit = manager->GetTargetAPZC(ScreenPoint(2, 2), matrix, matrix);
|
||||
EXPECT_EQ(layers[3]->AsContainerLayer()->GetAsyncPanZoomController(), hit.get());
|
||||
// expect hit point at LayerPoint(20, 20)
|
||||
|
||||
|
@ -457,7 +458,7 @@ TEST(APZCTreeManager, GetAPZCAtPoint) {
|
|||
|
||||
manager->UpdatePanZoomControllerTree(nullptr, root, 0, false);
|
||||
// layer 7 effective visible screenrect (0,16,4,60) but clipped by parent layers
|
||||
hit = manager->GetTargetAPZC(ScreenPoint(1, 45));
|
||||
hit = manager->GetTargetAPZC(ScreenPoint(1, 45), matrix, matrix);
|
||||
EXPECT_EQ(layers[7]->AsContainerLayer()->GetAsyncPanZoomController(), hit.get());
|
||||
// expect hit point at LayerPoint(20, 29)
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче