bool ClientLayerManager::ProgressiveUpdateCallback(bool aHasPendingNewThebesContent, FrameMetrics& aMetrics, bool aDrawingCritical) { #ifdef MOZ_WIDGET_ANDROID MOZ_ASSERT(aMetrics.IsScrollable()); // This is derived from the code in // gfx/layers/ipc/CompositorParent.cpp::TransformShadowTree. CSSToLayerScale paintScale = aMetrics.LayersPixelsPerCSSPixel().ToScaleFactor(); const CSSRect& metricsDisplayPort = (aDrawingCritical && !aMetrics.GetCriticalDisplayPort().IsEmpty()) ? aMetrics.GetCriticalDisplayPort() : aMetrics.GetDisplayPort(); LayerRect displayPort = (metricsDisplayPort + aMetrics.GetScrollOffset()) * paintScale; ParentLayerPoint scrollOffset; CSSToParentLayerScale zoom; bool ret = AndroidBridge::Bridge()->ProgressiveUpdateCallback( aHasPendingNewThebesContent, displayPort, paintScale.scale, aDrawingCritical, scrollOffset, zoom); aMetrics.SetScrollOffset(scrollOffset / zoom); aMetrics.SetZoom(CSSToParentLayerScale2D(zoom)); return ret; #else return false; #endif }
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; }
void APZCCallbackHelper::UpdateSubFrame(nsIContent* aContent, FrameMetrics& aMetrics) { // Precondition checks MOZ_ASSERT(aContent); MOZ_ASSERT(aMetrics.GetUseDisplayPortMargins()); if (aMetrics.GetScrollId() == FrameMetrics::NULL_SCROLL_ID) { return; } nsCOMPtr<nsIDOMWindowUtils> utils = GetDOMWindowUtils(aContent); if (!utils) { return; } // We currently do not support zooming arbitrary subframes. They can only // be scrolled, so here we only have to set the scroll position and displayport. nsIScrollableFrame* sf = nsLayoutUtils::FindScrollableFrameFor(aMetrics.GetScrollId()); bool scrollUpdated = false; CSSPoint actualScrollOffset = ScrollFrameTo(sf, aMetrics.GetScrollOffset(), scrollUpdated); nsCOMPtr<nsIDOMElement> element = do_QueryInterface(aContent); if (element) { if (scrollUpdated) { AdjustDisplayPortForScrollDelta(aMetrics, actualScrollOffset); } else { RecenterDisplayPort(aMetrics); } gfx::IntSize alignment = gfxPrefs::LayersTilesEnabled() ? gfx::IntSize(gfxPrefs::LayersTileWidth(), gfxPrefs::LayersTileHeight()) : gfx::IntSize(0, 0); LayerMargin margins = aMetrics.GetDisplayPortMargins(); utils->SetDisplayPortMarginsForElement(margins.left, margins.top, margins.right, margins.bottom, alignment.width, alignment.height, element, 0); CSSRect baseCSS = aMetrics.CalculateCompositedRectInCssPixels(); nsRect base(baseCSS.x * nsPresContext::AppUnitsPerCSSPixel(), baseCSS.y * nsPresContext::AppUnitsPerCSSPixel(), baseCSS.width * nsPresContext::AppUnitsPerCSSPixel(), baseCSS.height * nsPresContext::AppUnitsPerCSSPixel()); nsLayoutUtils::SetDisplayPortBaseIfNotSet(aContent, base); } aMetrics.SetScrollOffset(actualScrollOffset); }
/** * Scroll the scroll frame associated with |aContent| to the scroll position * requested in |aMetrics|. * The scroll offset in |aMetrics| is updated to reflect the actual scroll * position. * The displayport stored in |aMetrics| and the callback-transform stored on * the content are updated to reflect any difference between the requested * and actual scroll positions. */ static void ScrollFrame(nsIContent* aContent, FrameMetrics& aMetrics) { // Scroll the window to the desired spot nsIScrollableFrame* sf = nsLayoutUtils::FindScrollableFrameFor(aMetrics.GetScrollId()); if (sf) { sf->SetScrollableByAPZ(!aMetrics.IsScrollInfoLayer()); } bool scrollUpdated = false; CSSPoint apzScrollOffset = aMetrics.GetScrollOffset(); CSSPoint actualScrollOffset = ScrollFrameTo(sf, apzScrollOffset, scrollUpdated); if (scrollUpdated) { if (aMetrics.IsScrollInfoLayer()) { // In cases where the APZ scroll offset is different from the content scroll // offset, we want to interpret the margins as relative to the APZ scroll // offset except when the frame is not scrollable by APZ. Therefore, if the // layer is a scroll info layer, we leave the margins as-is and they will // be interpreted as relative to the content scroll offset. if (nsIFrame* frame = aContent->GetPrimaryFrame()) { frame->SchedulePaint(); } } else { // Correct the display port due to the difference between mScrollOffset and the // actual scroll offset. APZCCallbackHelper::AdjustDisplayPortForScrollDelta(aMetrics, actualScrollOffset); } } else { // For whatever reason we couldn't update the scroll offset on the scroll frame, // which means the data APZ used for its displayport calculation is stale. Fall // back to a sane default behaviour. Note that we don't tile-align the recentered // displayport because tile-alignment depends on the scroll position, and the // scroll position here is out of our control. See bug 966507 comment 21 for a // more detailed explanation. RecenterDisplayPort(aMetrics); } aMetrics.SetScrollOffset(actualScrollOffset); // APZ transforms inputs assuming we applied the exact scroll offset it // requested (|apzScrollOffset|). Since we may not have, record the difference // between what APZ asked for and what we actually applied, and apply it to // input events to compensate. if (aContent) { CSSPoint scrollDelta = apzScrollOffset - actualScrollOffset; aContent->SetProperty(nsGkAtoms::apzCallbackTransform, new CSSPoint(scrollDelta), nsINode::DeleteProperty<CSSPoint>); } }
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); }
/** * Scroll the scroll frame associated with |aContent| to the scroll position * requested in |aMetrics|. * The scroll offset in |aMetrics| is updated to reflect the actual scroll * position. * The displayport stored in |aMetrics| and the callback-transform stored on * the content are updated to reflect any difference between the requested * and actual scroll positions. */ static void ScrollFrame(nsIContent* aContent, FrameMetrics& aMetrics) { // Scroll the window to the desired spot nsIScrollableFrame* sf = nsLayoutUtils::FindScrollableFrameFor(aMetrics.GetScrollId()); bool scrollUpdated = false; CSSPoint apzScrollOffset = aMetrics.GetScrollOffset(); CSSPoint actualScrollOffset = ScrollFrameTo(sf, apzScrollOffset, scrollUpdated); if (scrollUpdated) { // Correct the display port due to the difference between mScrollOffset and the // actual scroll offset. AdjustDisplayPortForScrollDelta(aMetrics, actualScrollOffset); } else { // For whatever reason we couldn't update the scroll offset on the scroll frame, // which means the data APZ used for its displayport calculation is stale. Fall // back to a sane default behaviour. Note that we don't tile-align the recentered // displayport because tile-alignment depends on the scroll position, and the // scroll position here is out of our control. See bug 966507 comment 21 for a // more detailed explanation. RecenterDisplayPort(aMetrics); } aMetrics.SetScrollOffset(actualScrollOffset); // APZ transforms inputs assuming we applied the exact scroll offset it // requested (|apzScrollOffset|). Since we may not have, record the difference // between what APZ asked for and what we actually applied, and apply it to // input events to compensate. if (aContent) { CSSPoint scrollDelta = apzScrollOffset - actualScrollOffset; aContent->SetProperty(nsGkAtoms::apzCallbackTransform, new CSSPoint(scrollDelta), nsINode::DeleteProperty<CSSPoint>); } }
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); } }
/** * Advances a fling by an interpolated amount based on the Android OverScroller. * This should be called whenever sampling the content transform for this * frame. Returns true if the fling animation should be advanced by one frame, * or false if there is no fling or the fling has ended. */ bool AndroidFlingAnimation::DoSample(FrameMetrics& aFrameMetrics, const TimeDuration& aDelta) { bool shouldContinueFling = true; mFlingDuration += aDelta.ToMilliseconds(); mOverScroller->ComputeScrollOffset(mFlingDuration, &shouldContinueFling); int32_t currentX = 0; int32_t currentY = 0; mOverScroller->GetCurrX(¤tX); mOverScroller->GetCurrY(¤tY); ParentLayerPoint offset((float)currentX, (float)currentY); ParentLayerPoint preCheckedOffset(offset); bool hitBoundX = CheckBounds(mApzc.mX, offset.x, mFlingDirection.x, &(offset.x)); bool hitBoundY = CheckBounds(mApzc.mY, offset.y, mFlingDirection.y, &(offset.y)); ParentLayerPoint velocity = mPreviousVelocity; // Sometimes the OverScroller fails to update the offset for a frame. // If the frame can still scroll we just use the velocity from the previous // frame. However, if the frame can no longer scroll in the direction // of the fling, then end the animation. if (offset != mPreviousOffset) { if (aDelta.ToMilliseconds() > 0) { mOverScroller->GetCurrSpeedX(&velocity.x); mOverScroller->GetCurrSpeedY(&velocity.y); velocity.x /= 1000; velocity.y /= 1000; mPreviousVelocity = velocity; } } else if ((fabsf(offset.x - preCheckedOffset.x) > BOUNDS_EPSILON) || (fabsf(offset.y - preCheckedOffset.y) > BOUNDS_EPSILON)) { // The page is no longer scrolling but the fling animation is still animating beyond the page bounds. If it goes // beyond the BOUNDS_EPSILON then it has overflowed and will never stop. In that case, stop the fling animation. shouldContinueFling = false; } else if (hitBoundX && hitBoundY) { // We can't scroll any farther along either axis. shouldContinueFling = false; } float speed = velocity.Length(); // gfxPrefs::APZFlingStoppedThreshold is only used in tests. if (!shouldContinueFling || (speed < gfxPrefs::APZFlingStoppedThreshold())) { if (shouldContinueFling) { // The OverScroller thinks it should continue but the speed is below // the stopping threshold so abort the animation. mOverScroller->AbortAnimation(); } // This animation is going to end. If DeferHandleFlingOverscroll // has not been called and there is still some velocity left, // call it so that fling hand off may occur if applicable. if (!mSentBounceX && !mSentBounceY && (speed > 0.0f)) { DeferHandleFlingOverscroll(velocity); } return false; } mPreviousOffset = offset; mApzc.SetVelocityVector(velocity); aFrameMetrics.SetScrollOffset(offset / aFrameMetrics.GetZoom()); // If we hit a bounds while flinging, send the velocity so that the bounce // animation can play. if (hitBoundX || hitBoundY) { ParentLayerPoint bounceVelocity = velocity; if (!mSentBounceX && hitBoundX && fabsf(offset.x - mStartOffset.x) > BOUNDS_EPSILON) { mSentBounceX = true; } else { bounceVelocity.x = 0.0f; } if (!mSentBounceY && hitBoundY && fabsf(offset.y - mStartOffset.y) > BOUNDS_EPSILON) { mSentBounceY = true; } else { bounceVelocity.y = 0.0f; } if (!IsZero(bounceVelocity)) { DeferHandleFlingOverscroll(bounceVelocity); } } return true; }
/** * Advances a fling by an interpolated amount based on the Android OverScroller. * This should be called whenever sampling the content transform for this * frame. Returns true if the fling animation should be advanced by one frame, * or false if there is no fling or the fling has ended. */ bool AndroidFlingAnimation::DoSample(FrameMetrics& aFrameMetrics, const TimeDuration& aDelta) { bool shouldContinueFling = true; mOverScroller->ComputeScrollOffset(&shouldContinueFling); // OverScroller::GetCurrVelocity will sometimes return NaN. So need to externally // calculate current velocity and not rely on what the OverScroller calculates. // mOverScroller->GetCurrVelocity(&speed); int32_t currentX = 0; int32_t currentY = 0; mOverScroller->GetCurrX(¤tX); mOverScroller->GetCurrY(¤tY); ParentLayerPoint offset((float)currentX, (float)currentY); bool hitBoundX = CheckBounds(mApzc.mX, offset.x, mFlingDirection.x, &(offset.x)); bool hitBoundY = CheckBounds(mApzc.mY, offset.y, mFlingDirection.y, &(offset.y)); ParentLayerPoint velocity = mPreviousVelocity; // Sometimes the OverScroller fails to update the offset for a frame. // If the frame can still scroll we just use the velocity from the previous // frame. However, if the frame can no longer scroll in the direction // of the fling, then end the animation. if (offset != mPreviousOffset) { if (aDelta.ToMilliseconds() > 0) { velocity = (offset - mPreviousOffset) / (float)aDelta.ToMilliseconds(); mPreviousVelocity = velocity; } } else if (hitBoundX || hitBoundY) { // We have reached the end of the scroll in one of the directions being scrolled and the offset has not // changed so end animation. shouldContinueFling = false; } float speed = velocity.Length(); // gfxPrefs::APZFlingStoppedThreshold is only used in tests. if (!shouldContinueFling || (speed < gfxPrefs::APZFlingStoppedThreshold())) { if (shouldContinueFling) { // The OverScroller thinks it should continue but the speed is below // the stopping threshold so abort the animation. mOverScroller->AbortAnimation(); } // This animation is going to end. If DeferHandleFlingOverscroll // has not been called and there is still some velocity left, // call it so that fling hand off may occur if applicable. if (!mSentBounceX && !mSentBounceY && (speed > 0.0f)) { DeferHandleFlingOverscroll(velocity); } return false; } mPreviousOffset = offset; mApzc.SetVelocityVector(velocity); aFrameMetrics.SetScrollOffset(offset / aFrameMetrics.GetZoom()); // If we hit a bounds while flinging, send the velocity so that the bounce // animation can play. if (hitBoundX || hitBoundY) { ParentLayerPoint bounceVelocity = velocity; if (!mSentBounceX && hitBoundX && fabsf(offset.x - mStartOffset.x) > BOUNDS_EPSILON) { mSentBounceX = true; } else { bounceVelocity.x = 0.0f; } if (!mSentBounceY && hitBoundY && fabsf(offset.y - mStartOffset.y) > BOUNDS_EPSILON) { mSentBounceY = true; } else { bounceVelocity.y = 0.0f; } if (!IsZero(bounceVelocity)) { DeferHandleFlingOverscroll(bounceVelocity); } } return true; }
void APZCCallbackHelper::UpdateRootFrame(nsIDOMWindowUtils* aUtils, FrameMetrics& aMetrics) { // Precondition checks MOZ_ASSERT(aUtils); MOZ_ASSERT(aMetrics.GetUseDisplayPortMargins()); if (aMetrics.GetScrollId() == FrameMetrics::NULL_SCROLL_ID) { return; } // Set the scroll port size, which determines the scroll range. For example if // a 500-pixel document is shown in a 100-pixel frame, the scroll port length would // be 100, and gecko would limit the maximum scroll offset to 400 (so as to prevent // overscroll). Note that if the content here was zoomed to 2x, the document would // be 1000 pixels long but the frame would still be 100 pixels, and so the maximum // scroll range would be 900. Therefore this calculation depends on the zoom applied // to the content relative to the container. CSSSize scrollPort = aMetrics.CalculateCompositedSizeInCssPixels(); aUtils->SetScrollPositionClampingScrollPortSize(scrollPort.width, scrollPort.height); // Scroll the window to the desired spot nsIScrollableFrame* sf = nsLayoutUtils::FindScrollableFrameFor(aMetrics.GetScrollId()); bool scrollUpdated = false; CSSPoint actualScrollOffset = ScrollFrameTo(sf, aMetrics.GetScrollOffset(), scrollUpdated); if (scrollUpdated) { // Correct the display port due to the difference between mScrollOffset and the // actual scroll offset. AdjustDisplayPortForScrollDelta(aMetrics, actualScrollOffset); } else { // For whatever reason we couldn't update the scroll offset on the scroll frame, // which means the data APZ used for its displayport calculation is stale. Fall // back to a sane default behaviour. Note that we don't tile-align the recentered // displayport because tile-alignment depends on the scroll position, and the // scroll position here is out of our control. See bug 966507 comment 21 for a // more detailed explanation. RecenterDisplayPort(aMetrics); } aMetrics.SetScrollOffset(actualScrollOffset); // The mZoom variable on the frame metrics stores the CSS-to-screen scale for this // frame. This scale includes all of the (cumulative) resolutions set on the presShells // from the root down to this frame. However, when setting the resolution, we only // want the piece of the resolution that corresponds to this presShell, rather than // all of the cumulative stuff, so we need to divide out the parent resolutions. // Finally, we multiply by a ScreenToLayerScale of 1.0f because the goal here is to // take the async zoom calculated by the APZC and tell gecko about it (turning it into // a "sync" zoom) which will update the resolution at which the layer is painted. ParentLayerToLayerScale presShellResolution = aMetrics.GetZoom() / aMetrics.mDevPixelsPerCSSPixel / aMetrics.GetParentResolution() * ScreenToLayerScale(1.0f); aUtils->SetResolution(presShellResolution.scale, presShellResolution.scale); // Finally, we set the displayport. nsCOMPtr<nsIContent> content = nsLayoutUtils::FindContentFor(aMetrics.GetScrollId()); if (!content) { return; } nsCOMPtr<nsIDOMElement> element = do_QueryInterface(content); if (!element) { return; } gfx::IntSize alignment = gfxPrefs::LayersTilesEnabled() ? gfx::IntSize(gfxPrefs::LayersTileWidth(), gfxPrefs::LayersTileHeight()) : gfx::IntSize(0, 0); LayerMargin margins = aMetrics.GetDisplayPortMargins(); aUtils->SetDisplayPortMarginsForElement(margins.left, margins.top, margins.right, margins.bottom, alignment.width, alignment.height, element, 0); CSSRect baseCSS = aMetrics.CalculateCompositedRectInCssPixels(); nsRect base(baseCSS.x * nsPresContext::AppUnitsPerCSSPixel(), baseCSS.y * nsPresContext::AppUnitsPerCSSPixel(), baseCSS.width * nsPresContext::AppUnitsPerCSSPixel(), baseCSS.height * nsPresContext::AppUnitsPerCSSPixel()); nsLayoutUtils::SetDisplayPortBaseIfNotSet(content, base); }
void APZCCallbackHelper::UpdateRootFrame(nsIDOMWindowUtils* aUtils, FrameMetrics& aMetrics) { // Precondition checks MOZ_ASSERT(aUtils); MOZ_ASSERT(aMetrics.GetUseDisplayPortMargins()); if (aMetrics.GetScrollId() == FrameMetrics::NULL_SCROLL_ID) { return; } // Set the scroll port size, which determines the scroll range. For example if // a 500-pixel document is shown in a 100-pixel frame, the scroll port length would // be 100, and gecko would limit the maximum scroll offset to 400 (so as to prevent // overscroll). Note that if the content here was zoomed to 2x, the document would // be 1000 pixels long but the frame would still be 100 pixels, and so the maximum // scroll range would be 900. Therefore this calculation depends on the zoom applied // to the content relative to the container. CSSSize scrollPort = aMetrics.CalculateCompositedSizeInCssPixels(); aUtils->SetScrollPositionClampingScrollPortSize(scrollPort.width, scrollPort.height); // Scroll the window to the desired spot nsIScrollableFrame* sf = nsLayoutUtils::FindScrollableFrameFor(aMetrics.GetScrollId()); bool scrollUpdated = false; CSSPoint actualScrollOffset = ScrollFrameTo(sf, aMetrics.GetScrollOffset(), scrollUpdated); if (scrollUpdated) { // Correct the display port due to the difference between mScrollOffset and the // actual scroll offset. AdjustDisplayPortForScrollDelta(aMetrics, actualScrollOffset); } else { // For whatever reason we couldn't update the scroll offset on the scroll frame, // which means the data APZ used for its displayport calculation is stale. Fall // back to a sane default behaviour. Note that we don't tile-align the recentered // displayport because tile-alignment depends on the scroll position, and the // scroll position here is out of our control. See bug 966507 comment 21 for a // more detailed explanation. RecenterDisplayPort(aMetrics); } aMetrics.SetScrollOffset(actualScrollOffset); // The pres shell resolution is updated by the the async zoom since the // last paint. float presShellResolution = aMetrics.GetPresShellResolution() * aMetrics.GetAsyncZoom().scale; aUtils->SetResolutionAndScaleTo(presShellResolution, presShellResolution); // Finally, we set the displayport. nsCOMPtr<nsIContent> content = nsLayoutUtils::FindContentFor(aMetrics.GetScrollId()); if (!content) { return; } nsCOMPtr<nsIDOMElement> element = do_QueryInterface(content); if (!element) { return; } ScreenMargin margins = aMetrics.GetDisplayPortMargins(); aUtils->SetDisplayPortMarginsForElement(margins.left, margins.top, margins.right, margins.bottom, element, 0); CSSRect baseCSS = aMetrics.CalculateCompositedRectInCssPixels(); nsRect base(0, 0, baseCSS.width * nsPresContext::AppUnitsPerCSSPixel(), baseCSS.height * nsPresContext::AppUnitsPerCSSPixel()); nsLayoutUtils::SetDisplayPortBaseIfNotSet(content, base); }