TEST_F(APZHitTestingTester, Bug1148350) { CreateBug1148350LayerTree(); ScopedLayerTreeRegistration registration(manager, 0, root, mcc); manager->UpdateHitTestingTree(nullptr, root, false, 0, 0); MockFunction<void(std::string checkPointName)> check; { InSequence s; EXPECT_CALL(*mcc, HandleSingleTap(CSSPoint(100, 100), 0, ApzcOf(layers[1])->GetGuid())).Times(1); EXPECT_CALL(check, Call("Tapped without transform")); EXPECT_CALL(*mcc, HandleSingleTap(CSSPoint(100, 100), 0, ApzcOf(layers[1])->GetGuid())).Times(1); EXPECT_CALL(check, Call("Tapped with interleaved transform")); } Tap(manager, ScreenIntPoint(100, 100), TimeDuration::FromMilliseconds(100)); mcc->RunThroughDelayedTasks(); check.Call("Tapped without transform"); uint64_t blockId; TouchDown(manager, ScreenIntPoint(100, 100), mcc->Time(), &blockId); if (gfxPrefs::TouchActionEnabled()) { SetDefaultAllowedTouchBehavior(manager, blockId); } mcc->AdvanceByMillis(100); layers[0]->SetVisibleRegion(LayerIntRegion(LayerIntRect(0,50,200,150))); layers[0]->SetBaseTransform(Matrix4x4::Translation(0, 50, 0)); manager->UpdateHitTestingTree(nullptr, root, false, 0, 0); TouchUp(manager, ScreenIntPoint(100, 100), mcc->Time()); mcc->RunThroughDelayedTasks(); check.Call("Tapped with interleaved transform"); }
void DoLongPressTest(uint32_t aBehavior) { MakeApzcUnzoomable(); uint64_t blockId = 0; nsEventStatus status = TouchDown(apzc, ScreenIntPoint(10, 10), mcc->Time(), &blockId); EXPECT_EQ(nsEventStatus_eConsumeDoDefault, status); if (gfxPrefs::TouchActionEnabled() && status != nsEventStatus_eConsumeNoDefault) { // SetAllowedTouchBehavior() must be called after sending touch-start. nsTArray<uint32_t> allowedTouchBehaviors; allowedTouchBehaviors.AppendElement(aBehavior); apzc->SetAllowedTouchBehavior(blockId, allowedTouchBehaviors); } // Have content "respond" to the touchstart apzc->ContentReceivedInputBlock(blockId, false); MockFunction<void(std::string checkPointName)> check; { InSequence s; EXPECT_CALL(check, Call("preHandleLongTap")); blockId++; EXPECT_CALL(*mcc, HandleLongTap(CSSPoint(10, 10), 0, apzc->GetGuid(), blockId)).Times(1); EXPECT_CALL(check, Call("postHandleLongTap")); EXPECT_CALL(check, Call("preHandleSingleTap")); EXPECT_CALL(*mcc, HandleSingleTap(CSSPoint(10, 10), 0, apzc->GetGuid())).Times(1); EXPECT_CALL(check, Call("postHandleSingleTap")); } // Manually invoke the longpress while the touch is currently down. check.Call("preHandleLongTap"); mcc->RunThroughDelayedTasks(); check.Call("postHandleLongTap"); // Dispatching the longpress event starts a new touch block, which // needs a new content response and also has a pending timeout task // in the queue. Deal with those here. We do the content response first // with preventDefault=false, and then we run the timeout task which // "loses the race" and does nothing. apzc->ContentReceivedInputBlock(blockId, false); mcc->AdvanceByMillis(1000); // Finally, simulate lifting the finger. Since the long-press wasn't // prevent-defaulted, we should get a long-tap-up event. check.Call("preHandleSingleTap"); status = TouchUp(apzc, ScreenIntPoint(10, 10), mcc->Time()); mcc->RunThroughDelayedTasks(); EXPECT_EQ(nsEventStatus_eConsumeDoDefault, status); check.Call("postHandleSingleTap"); apzc->AssertStateIsReset(); }
TEST_F(APZCGestureDetectorTester, TapFollowedByMultipleTouches) { MakeApzcZoomable(); EXPECT_CALL(*mcc, HandleSingleTap(CSSPoint(10, 10), 0, apzc->GetGuid())).Times(1); Tap(apzc, ScreenIntPoint(10, 10), TimeDuration::FromMilliseconds(100)); int inputId = 0; MultiTouchInput mti; mti = CreateMultiTouchInput(MultiTouchInput::MULTITOUCH_START, mcc->Time()); mti.mTouches.AppendElement(SingleTouchData(inputId, ParentLayerPoint(20, 20), ScreenSize(0, 0), 0, 0)); apzc->ReceiveInputEvent(mti, nullptr); mti = CreateMultiTouchInput(MultiTouchInput::MULTITOUCH_START, mcc->Time()); mti.mTouches.AppendElement(SingleTouchData(inputId, ParentLayerPoint(20, 20), ScreenSize(0, 0), 0, 0)); mti.mTouches.AppendElement(SingleTouchData(inputId + 1, ParentLayerPoint(10, 10), ScreenSize(0, 0), 0, 0)); apzc->ReceiveInputEvent(mti, nullptr); mti = CreateMultiTouchInput(MultiTouchInput::MULTITOUCH_END, mcc->Time()); mti.mTouches.AppendElement(SingleTouchData(inputId, ParentLayerPoint(20, 20), ScreenSize(0, 0), 0, 0)); mti.mTouches.AppendElement(SingleTouchData(inputId + 1, ParentLayerPoint(10, 10), ScreenSize(0, 0), 0, 0)); apzc->ReceiveInputEvent(mti, nullptr); apzc->AssertStateIsReset(); }
TEST_F(APZCGestureDetectorTester, DoubleTapPreventDefaultBoth) { MakeApzcWaitForMainThread(); MakeApzcZoomable(); EXPECT_CALL(*mcc, HandleSingleTap(CSSPoint(10, 10), 0, apzc->GetGuid())).Times(0); EXPECT_CALL(*mcc, HandleDoubleTap(CSSPoint(10, 10), 0, apzc->GetGuid())).Times(0); uint64_t blockIds[2]; DoubleTapAndCheckStatus(apzc, ScreenIntPoint(10, 10), &blockIds); // responses to the two touchstarts apzc->ContentReceivedInputBlock(blockIds[0], true); apzc->ContentReceivedInputBlock(blockIds[1], true); apzc->AssertStateIsReset(); }
ClientTiledThebesLayer::ClientTiledThebesLayer(ClientLayerManager* const aManager) : ThebesLayer(aManager, static_cast<ClientLayer*>(this)) , mContentClient() { MOZ_COUNT_CTOR(ClientTiledThebesLayer); mPaintData.mLastScrollOffset = CSSPoint(0, 0); mPaintData.mFirstPaint = true; }
already_AddRefed<DOMQuad> ConvertRectFromNode(nsINode* aTo, dom::DOMRectReadOnly& aRect, const GeometryNode& aFrom, const dom::ConvertCoordinateOptions& aOptions, ErrorResult& aRv) { CSSPoint points[4]; double x = aRect.X(), y = aRect.Y(), w = aRect.Width(), h = aRect.Height(); points[0] = CSSPoint(x, y); points[1] = CSSPoint(x + w, y); points[2] = CSSPoint(x + w, y + h); points[3] = CSSPoint(x, y + h); TransformPoints(aTo, aFrom, 4, points, aOptions, aRv); if (aRv.Failed()) { return nullptr; } RefPtr<DOMQuad> result = new DOMQuad(aTo->GetParentObject().mObject, points); return result.forget(); }
FrameMetrics GetPinchableFrameMetrics() { FrameMetrics fm; fm.SetCompositionBounds(ParentLayerRect(200, 200, 100, 200)); fm.SetScrollableRect(CSSRect(0, 0, 980, 1000)); fm.SetScrollOffset(CSSPoint(300, 300)); fm.SetZoom(CSSToParentLayerScale2D(2.0, 2.0)); // APZC only allows zooming on the root scrollable frame. fm.SetIsRootContent(true); // the visible area of the document in CSS pixels is x=300 y=300 w=50 h=100 return fm; }
mozilla::ipc::IPCResult WebRenderBridgeParent::RecvSetAsyncScrollOffset(const FrameMetrics::ViewID& aScrollId, const float& aX, const float& aY) { if (mDestroyed) { return IPC_OK(); } RefPtr<AsyncPanZoomController> apzc = GetTargetAPZC(aScrollId); if (!apzc) { return IPC_FAIL_NO_REASON(this); } apzc->SetTestAsyncScrollOffset(CSSPoint(aX, aY)); return IPC_OK(); }
TEST_F(APZEventRegionsTester, Bug1117712) { CreateBug1117712LayerTree(); TestAsyncPanZoomController* apzc2 = ApzcOf(layers[2]); // These touch events should hit the dispatch-to-content region of layers[3] // and so get queued with that APZC as the tentative target. uint64_t inputBlockId = 0; Tap(manager, 55, 5, mcc, TimeDuration::FromMilliseconds(100), nullptr, &inputBlockId); // But now we tell the APZ that really it hit layers[2], and expect the tap // to be delivered at the correct coordinates. EXPECT_CALL(*mcc, HandleSingleTap(CSSPoint(55, 5), 0, apzc2->GetGuid())).Times(1); nsTArray<ScrollableLayerGuid> targets; targets.AppendElement(apzc2->GetGuid()); manager->SetTargetAPZC(inputBlockId, targets); }
TEST_F(APZCGestureDetectorTester, MediumPress) { MakeApzcUnzoomable(); MockFunction<void(std::string checkPointName)> check; { InSequence s; // This verifies that the single tap notification is sent after the // touchup is fully processed. The ordering here is important. EXPECT_CALL(check, Call("pre-tap")); EXPECT_CALL(check, Call("post-tap")); EXPECT_CALL(*mcc, HandleSingleTap(CSSPoint(10, 10), 0, apzc->GetGuid())).Times(1); } check.Call("pre-tap"); TapAndCheckStatus(apzc, ScreenIntPoint(10, 10), TimeDuration::FromMilliseconds(400)); check.Call("post-tap"); apzc->AssertStateIsReset(); }
static CSSPoint ScrollFrameTo(nsIScrollableFrame* aFrame, const CSSPoint& aPoint, bool& aSuccessOut) { aSuccessOut = false; if (!aFrame) { return CSSPoint(); } CSSPoint targetScrollPosition = aPoint; // If the frame is overflow:hidden on a particular axis, we don't want to allow // user-driven scroll on that axis. Simply set the scroll position on that axis // to whatever it already is. Note that this will leave the APZ's async scroll // position out of sync with the gecko scroll position, but APZ can deal with that // (by design). Note also that when we run into this case, even if both axes // have overflow:hidden, we want to set aSuccessOut to true, so that the displayport // follows the async scroll position rather than the gecko scroll position. CSSPoint geckoScrollPosition = CSSPoint::FromAppUnits(aFrame->GetScrollPosition()); if (aFrame->GetScrollbarStyles().mVertical == NS_STYLE_OVERFLOW_HIDDEN) { targetScrollPosition.y = geckoScrollPosition.y; } if (aFrame->GetScrollbarStyles().mHorizontal == NS_STYLE_OVERFLOW_HIDDEN) { targetScrollPosition.x = geckoScrollPosition.x; } // If the scrollable frame is currently in the middle of an async or smooth // scroll then we don't want to interrupt it (see bug 961280). // Also if the scrollable frame got a scroll request from something other than us // since the last layers update, then we don't want to push our scroll request // because we'll clobber that one, which is bad. if (!aFrame->IsProcessingAsyncScroll() && (!aFrame->OriginOfLastScroll() || aFrame->OriginOfLastScroll() == nsGkAtoms::apz)) { aFrame->ScrollToCSSPixelsApproximate(targetScrollPosition, nsGkAtoms::apz); geckoScrollPosition = CSSPoint::FromAppUnits(aFrame->GetScrollPosition()); aSuccessOut = true; } // Return the final scroll position after setting it so that anything that relies // on it can have an accurate value. Note that even if we set it above re-querying it // is a good idea because it may have gotten clamped or rounded. return geckoScrollPosition; }
TEST_F(APZCGestureDetectorTester, TapTimeoutInterruptedByWheel) { // In this test, even though the wheel block comes right after the tap, the // tap should still be dispatched because it completes fully before the wheel // block arrived. EXPECT_CALL(*mcc, HandleSingleTap(CSSPoint(10, 10), 0, apzc->GetGuid())).Times(1); // We make the APZC zoomable so the gesture detector needs to wait to // distinguish between tap and double-tap. During that timeout is when we // insert the wheel event. MakeApzcZoomable(); uint64_t touchBlockId = 0; uint64_t wheelBlockId = 0; Tap(apzc, ScreenIntPoint(10, 10), TimeDuration::FromMilliseconds(100), nullptr, &touchBlockId); mcc->AdvanceByMillis(10); Wheel(apzc, ScreenIntPoint(10, 10), ScreenPoint(0, -10), mcc->Time(), &wheelBlockId); EXPECT_NE(touchBlockId, wheelBlockId); while (mcc->RunThroughDelayedTasks()); }
TEST_F(APZHitTestingTester, HitTestingRespectsScrollClip_Bug1257288) { // Create the layer tree. const char* layerTreeSyntax = "c(tt)"; // LayerID 0 12 nsIntRegion layerVisibleRegion[] = { nsIntRegion(IntRect(0,0,200,200)), nsIntRegion(IntRect(0,0,200,200)), nsIntRegion(IntRect(0,0,200,100)) }; root = CreateLayerTree(layerTreeSyntax, layerVisibleRegion, nullptr, lm, layers); // Add root scroll metadata to the first painted layer. SetScrollableFrameMetrics(layers[1], FrameMetrics::START_SCROLL_ID, CSSRect(0,0,200,200)); // Add root and subframe scroll metadata to the second painted layer. // Give the subframe metadata a scroll clip corresponding to the subframe's // composition bounds. // Importantly, give the layer a layer clip which leaks outside of the // subframe's composition bounds. ScrollMetadata rootMetadata = BuildScrollMetadata( FrameMetrics::START_SCROLL_ID, CSSRect(0,0,200,200), ParentLayerRect(0,0,200,200)); ScrollMetadata subframeMetadata = BuildScrollMetadata( FrameMetrics::START_SCROLL_ID + 1, CSSRect(0,0,200,200), ParentLayerRect(0,0,200,100)); subframeMetadata.SetScrollClip(Some(LayerClip(ParentLayerIntRect(0,0,200,100)))); layers[2]->SetScrollMetadata({subframeMetadata, rootMetadata}); layers[2]->SetClipRect(Some(ParentLayerIntRect(0,0,200,200))); SetEventRegionsBasedOnBottommostMetrics(layers[2]); // Build the hit testing tree. ScopedLayerTreeRegistration registration(manager, 0, root, mcc); manager->UpdateHitTestingTree(nullptr, root, false, 0, 0); // Pan on a region that's inside layers[2]'s layer clip, but outside // its subframe metadata's scroll clip. Pan(manager, 120, 110); // Test that the subframe hasn't scrolled. EXPECT_EQ(CSSPoint(0,0), ApzcOf(layers[2], 0)->GetFrameMetrics().GetScrollOffset()); }
static CSSPoint ScrollFrameTo(nsIScrollableFrame* aFrame, const CSSPoint& aPoint) { if (!aFrame) { return CSSPoint(); } // If the scrollable frame is currently in the middle of an async or smooth // scroll then we don't want to interrupt it (see bug 961280). // Also if the scrollable frame got a scroll request from something other than us // since the last layers update, then we don't want to push our scroll request // because we'll clobber that one, which is bad. if (!aFrame->IsProcessingAsyncScroll() && (!aFrame->OriginOfLastScroll() || aFrame->OriginOfLastScroll() == nsGkAtoms::apz)) { aFrame->ScrollToCSSPixelsApproximate(aPoint, nsGkAtoms::apz); } // Return the final scroll position after setting it so that anything that relies // on it can have an accurate value. Note that even if we set it above re-querying it // is a good idea because it may have gotten clamped or rounded. return CSSPoint::FromAppUnits(aFrame->GetScrollPosition()); }
already_AddRefed<DOMQuad> ConvertQuadFromNode(nsINode* aTo, dom::DOMQuad& aQuad, const GeometryNode& aFrom, const dom::ConvertCoordinateOptions& aOptions, ErrorResult& aRv) { CSSPoint points[4]; for (uint32_t i = 0; i < 4; ++i) { DOMPoint* p = aQuad.Point(i); if (p->W() != 1.0 || p->Z() != 0.0) { aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR); return nullptr; } points[i] = CSSPoint(p->X(), p->Y()); } TransformPoints(aTo, aFrom, 4, points, aOptions, aRv); if (aRv.Failed()) { return nullptr; } RefPtr<DOMQuad> result = new DOMQuad(aTo->GetParentObject().mObject, points); return result.forget(); }
TEST_F(APZCBasicTester, Overzoom) { // the visible area of the document in CSS pixels is x=10 y=0 w=100 h=100 FrameMetrics fm; fm.SetCompositionBounds(ParentLayerRect(0, 0, 100, 100)); fm.SetScrollableRect(CSSRect(0, 0, 125, 150)); fm.SetScrollOffset(CSSPoint(10, 0)); fm.SetZoom(CSSToParentLayerScale2D(1.0, 1.0)); fm.SetIsRootContent(true); apzc->SetFrameMetrics(fm); MakeApzcZoomable(); EXPECT_CALL(*mcc, RequestContentRepaint(_)).Times(1); PinchWithPinchInputAndCheckStatus(apzc, ScreenIntPoint(50, 50), 0.5, true); fm = apzc->GetFrameMetrics(); EXPECT_EQ(0.8f, fm.GetZoom().ToScaleFactor().scale); // bug 936721 - PGO builds introduce rounding error so // use a fuzzy match instead EXPECT_LT(std::abs(fm.GetScrollOffset().x), 1e-5); EXPECT_LT(std::abs(fm.GetScrollOffset().y), 1e-5); }
bool LayerTransactionParent::RecvSetAsyncScrollOffset(PLayerParent* aLayer, const int32_t& aX, const int32_t& aY) { if (mDestroyed || !layer_manager() || layer_manager()->IsDestroyed()) { return false; } Layer* layer = cast(aLayer)->AsLayer(); if (!layer) { return false; } ContainerLayer* containerLayer = layer->AsContainerLayer(); if (!containerLayer) { return false; } AsyncPanZoomController* controller = containerLayer->GetAsyncPanZoomController(); if (!controller) { return false; } controller->SetTestAsyncScrollOffset(CSSPoint(aX, aY)); return true; }
virtual void AddBox(nsIFrame* aFrame) override { nsIFrame* f = aFrame; nsRect box = GetBoxRectForFrame(&f, mBoxType); nsPoint appUnits[4] = { box.TopLeft(), box.TopRight(), box.BottomRight(), box.BottomLeft() }; CSSPoint points[4]; for (uint32_t i = 0; i < 4; ++i) { points[i] = CSSPoint(nsPresContext::AppUnitsToFloatCSSPixels(appUnits[i].x), nsPresContext::AppUnitsToFloatCSSPixels(appUnits[i].y)); } nsLayoutUtils::TransformResult rv = nsLayoutUtils::TransformPoints(f, mRelativeToFrame, 4, points); if (rv == nsLayoutUtils::TRANSFORM_SUCCEEDED) { CSSPoint delta(nsPresContext::AppUnitsToFloatCSSPixels(mRelativeToBoxTopLeft.x), nsPresContext::AppUnitsToFloatCSSPixels(mRelativeToBoxTopLeft.y)); for (uint32_t i = 0; i < 4; ++i) { points[i] -= delta; } } else { PodArrayZero(points); } mResult.AppendElement(new DOMQuad(mParentObject, points)); }
static CSSPoint ScrollFrameTo(nsIScrollableFrame* aFrame, const CSSPoint& aPoint) { if (!aFrame) { return CSSPoint(); } // If the scrollable frame got a scroll request from something other than us // since the last layers update, then we don't want to push our scroll request // because we'll clobber that one, which is bad. // Note that content may have just finished sending a layers update with a scroll // offset update to the APZ, in which case the origin will be reset to null and we // might actually be clobbering the content-side scroll offset with a stale APZ // scroll offset. This is unavoidable because of the async communication between // APZ and content; however the code in NotifyLayersUpdated should reissue a new // repaint request to bring everything back into sync. if (!aFrame->OriginOfLastScroll() || aFrame->OriginOfLastScroll() == nsGkAtoms::apz) { aFrame->ScrollToCSSPixelsApproximate(aPoint, nsGkAtoms::apz); } // Return the final scroll position after setting it so that anything that relies // on it can have an accurate value. Note that even if we set it above re-querying it // is a good idea because it may have gotten clamped or rounded. return CSSPoint::FromAppUnits(aFrame->GetScrollPosition()); }
void DoPinchTest(bool aShouldTriggerPinch, nsTArray<uint32_t> *aAllowedTouchBehaviors = nullptr) { apzc->SetFrameMetrics(GetPinchableFrameMetrics()); MakeApzcZoomable(); if (aShouldTriggerPinch) { // One repaint request for each gesture. EXPECT_CALL(*mcc, RequestContentRepaint(_)).Times(2); } else { EXPECT_CALL(*mcc, RequestContentRepaint(_)).Times(0); } int touchInputId = 0; if (mGestureBehavior == AsyncPanZoomController::USE_GESTURE_DETECTOR) { PinchWithTouchInputAndCheckStatus(apzc, 250, 300, 1.25, touchInputId, aShouldTriggerPinch, aAllowedTouchBehaviors); } else { PinchWithPinchInputAndCheckStatus(apzc, 250, 300, 1.25, aShouldTriggerPinch); } FrameMetrics fm = apzc->GetFrameMetrics(); if (aShouldTriggerPinch) { // the visible area of the document in CSS pixels is now x=305 y=310 w=40 h=80 EXPECT_EQ(2.5f, fm.GetZoom().ToScaleFactor().scale); EXPECT_EQ(305, fm.GetScrollOffset().x); EXPECT_EQ(310, fm.GetScrollOffset().y); } else { // The frame metrics should stay the same since touch-action:none makes // apzc ignore pinch gestures. EXPECT_EQ(2.0f, fm.GetZoom().ToScaleFactor().scale); EXPECT_EQ(300, fm.GetScrollOffset().x); EXPECT_EQ(300, fm.GetScrollOffset().y); } // part 2 of the test, move to the top-right corner of the page and pinch and // make sure we stay in the correct spot fm.SetZoom(CSSToParentLayerScale2D(2.0, 2.0)); fm.SetScrollOffset(CSSPoint(930, 5)); apzc->SetFrameMetrics(fm); // the visible area of the document in CSS pixels is x=930 y=5 w=50 h=100 if (mGestureBehavior == AsyncPanZoomController::USE_GESTURE_DETECTOR) { PinchWithTouchInputAndCheckStatus(apzc, 250, 300, 0.5, touchInputId, aShouldTriggerPinch, aAllowedTouchBehaviors); } else { PinchWithPinchInputAndCheckStatus(apzc, 250, 300, 0.5, aShouldTriggerPinch); } fm = apzc->GetFrameMetrics(); if (aShouldTriggerPinch) { // the visible area of the document in CSS pixels is now x=880 y=0 w=100 h=200 EXPECT_EQ(1.0f, fm.GetZoom().ToScaleFactor().scale); EXPECT_EQ(880, fm.GetScrollOffset().x); EXPECT_EQ(0, fm.GetScrollOffset().y); } else { EXPECT_EQ(2.0f, fm.GetZoom().ToScaleFactor().scale); EXPECT_EQ(930, fm.GetScrollOffset().x); EXPECT_EQ(5, fm.GetScrollOffset().y); } }
TEST_F(APZCBasicTester, ComplexTransform) { // This test assumes there is a page that gets rendered to // two layers. In CSS pixels, the first layer is 50x50 and // the second layer is 25x50. The widget scale factor is 3.0 // and the presShell resolution is 2.0. Therefore, these layers // end up being 300x300 and 150x300 in layer pixels. // // The second (child) layer has an additional CSS transform that // stretches it by 2.0 on the x-axis. Therefore, after applying // CSS transforms, the two layers are the same size in screen // pixels. // // The screen itself is 24x24 in screen pixels (therefore 4x4 in // CSS pixels). The displayport is 1 extra CSS pixel on all // sides. RefPtr<TestAsyncPanZoomController> childApzc = new TestAsyncPanZoomController(0, mcc, tm); const char* layerTreeSyntax = "c(c)"; // LayerID 0 1 nsIntRegion layerVisibleRegion[] = { nsIntRegion(IntRect(0, 0, 300, 300)), nsIntRegion(IntRect(0, 0, 150, 300)), }; Matrix4x4 transforms[] = { Matrix4x4(), Matrix4x4(), }; transforms[0].PostScale(0.5f, 0.5f, 1.0f); // this results from the 2.0 resolution on the root layer transforms[1].PostScale(2.0f, 1.0f, 1.0f); // this is the 2.0 x-axis CSS transform on the child layer nsTArray<RefPtr<Layer> > layers; RefPtr<LayerManager> lm; RefPtr<Layer> root = CreateLayerTree(layerTreeSyntax, layerVisibleRegion, transforms, lm, layers); ScrollMetadata metadata; FrameMetrics& metrics = metadata.GetMetrics(); metrics.SetCompositionBounds(ParentLayerRect(0, 0, 24, 24)); metrics.SetDisplayPort(CSSRect(-1, -1, 6, 6)); metrics.SetScrollOffset(CSSPoint(10, 10)); metrics.SetScrollableRect(CSSRect(0, 0, 50, 50)); metrics.SetCumulativeResolution(LayoutDeviceToLayerScale2D(2, 2)); metrics.SetPresShellResolution(2.0f); metrics.SetZoom(CSSToParentLayerScale2D(6, 6)); metrics.SetDevPixelsPerCSSPixel(CSSToLayoutDeviceScale(3)); metrics.SetScrollId(FrameMetrics::START_SCROLL_ID); ScrollMetadata childMetadata = metadata; FrameMetrics& childMetrics = childMetadata.GetMetrics(); childMetrics.SetScrollId(FrameMetrics::START_SCROLL_ID + 1); layers[0]->SetScrollMetadata(metadata); layers[1]->SetScrollMetadata(childMetadata); ParentLayerPoint pointOut; AsyncTransform viewTransformOut; // Both the parent and child layer should behave exactly the same here, because // the CSS transform on the child layer does not affect the SampleContentTransformForFrame code // initial transform apzc->SetFrameMetrics(metrics); apzc->NotifyLayersUpdated(metadata, true, true); apzc->SampleContentTransformForFrame(&viewTransformOut, pointOut); EXPECT_EQ(AsyncTransform(LayerToParentLayerScale(1), ParentLayerPoint()), viewTransformOut); EXPECT_EQ(ParentLayerPoint(60, 60), pointOut); childApzc->SetFrameMetrics(childMetrics); childApzc->NotifyLayersUpdated(childMetadata, true, true); childApzc->SampleContentTransformForFrame(&viewTransformOut, pointOut); EXPECT_EQ(AsyncTransform(LayerToParentLayerScale(1), ParentLayerPoint()), viewTransformOut); EXPECT_EQ(ParentLayerPoint(60, 60), pointOut); // do an async scroll by 5 pixels and check the transform metrics.ScrollBy(CSSPoint(5, 0)); apzc->SetFrameMetrics(metrics); apzc->SampleContentTransformForFrame(&viewTransformOut, pointOut); EXPECT_EQ(AsyncTransform(LayerToParentLayerScale(1), ParentLayerPoint(-30, 0)), viewTransformOut); EXPECT_EQ(ParentLayerPoint(90, 60), pointOut); childMetrics.ScrollBy(CSSPoint(5, 0)); childApzc->SetFrameMetrics(childMetrics); childApzc->SampleContentTransformForFrame(&viewTransformOut, pointOut); EXPECT_EQ(AsyncTransform(LayerToParentLayerScale(1), ParentLayerPoint(-30, 0)), viewTransformOut); EXPECT_EQ(ParentLayerPoint(90, 60), pointOut); // do an async zoom of 1.5x and check the transform metrics.ZoomBy(1.5f); apzc->SetFrameMetrics(metrics); apzc->SampleContentTransformForFrame(&viewTransformOut, pointOut); EXPECT_EQ(AsyncTransform(LayerToParentLayerScale(1.5), ParentLayerPoint(-45, 0)), viewTransformOut); EXPECT_EQ(ParentLayerPoint(135, 90), pointOut); childMetrics.ZoomBy(1.5f); childApzc->SetFrameMetrics(childMetrics); childApzc->SampleContentTransformForFrame(&viewTransformOut, pointOut); EXPECT_EQ(AsyncTransform(LayerToParentLayerScale(1.5), ParentLayerPoint(-45, 0)), viewTransformOut); EXPECT_EQ(ParentLayerPoint(135, 90), pointOut); childApzc->Destroy(); }
void DoLongPressPreventDefaultTest(uint32_t aBehavior) { MakeApzcUnzoomable(); EXPECT_CALL(*mcc, RequestContentRepaint(_)).Times(0); int touchX = 10, touchStartY = 10, touchEndY = 50; uint64_t blockId = 0; nsEventStatus status = TouchDown(apzc, ScreenIntPoint(touchX, touchStartY), mcc->Time(), &blockId); EXPECT_EQ(nsEventStatus_eConsumeDoDefault, status); if (gfxPrefs::TouchActionEnabled() && status != nsEventStatus_eConsumeNoDefault) { // SetAllowedTouchBehavior() must be called after sending touch-start. nsTArray<uint32_t> allowedTouchBehaviors; allowedTouchBehaviors.AppendElement(aBehavior); apzc->SetAllowedTouchBehavior(blockId, allowedTouchBehaviors); } // Have content "respond" to the touchstart apzc->ContentReceivedInputBlock(blockId, false); MockFunction<void(std::string checkPointName)> check; { InSequence s; EXPECT_CALL(check, Call("preHandleLongTap")); blockId++; EXPECT_CALL(*mcc, HandleLongTap(CSSPoint(touchX, touchStartY), 0, apzc->GetGuid(), blockId)).Times(1); EXPECT_CALL(check, Call("postHandleLongTap")); } // Manually invoke the longpress while the touch is currently down. check.Call("preHandleLongTap"); mcc->RunThroughDelayedTasks(); check.Call("postHandleLongTap"); // There should be a TimeoutContentResponse task in the queue still, // waiting for the response from the longtap event dispatched above. // Send the signal that content has handled the long-tap, and then run // the timeout task (it will be a no-op because the content "wins" the // race. This takes the place of the "contextmenu" event. apzc->ContentReceivedInputBlock(blockId, true); mcc->AdvanceByMillis(1000); MultiTouchInput mti = CreateMultiTouchInput(MultiTouchInput::MULTITOUCH_MOVE, mcc->Time()); mti.mTouches.AppendElement(SingleTouchData(0, ParentLayerPoint(touchX, touchEndY), ScreenSize(0, 0), 0, 0)); status = apzc->ReceiveInputEvent(mti, nullptr); EXPECT_EQ(nsEventStatus_eConsumeDoDefault, status); EXPECT_CALL(*mcc, HandleSingleTap(CSSPoint(touchX, touchEndY), 0, apzc->GetGuid())).Times(0); status = TouchUp(apzc, ScreenIntPoint(touchX, touchEndY), mcc->Time()); EXPECT_EQ(nsEventStatus_eConsumeDoDefault, status); ParentLayerPoint pointOut; AsyncTransform viewTransformOut; apzc->SampleContentTransformForFrame(&viewTransformOut, pointOut); EXPECT_EQ(ParentLayerPoint(), pointOut); EXPECT_EQ(AsyncTransform(), viewTransformOut); apzc->AssertStateIsReset(); }