Bug 966507 - Recenter the displayport around the composition bounds if layout doesn't accept the scroll update calculated by APZ. r=tn,Cwiiis

This commit is contained in:
Kartikaya Gupta 2014-02-19 09:50:46 -05:00
parent 9b8136826b
commit 0fa623e448

View File

@ -85,9 +85,19 @@ MaybeAlignAndClampDisplayPort(mozilla::layers::FrameMetrics& aFrameMetrics,
- aActualScrollOffset;
}
static CSSPoint
ScrollFrameTo(nsIScrollableFrame* aFrame, const CSSPoint& aPoint)
static void
RecenterDisplayPort(mozilla::layers::FrameMetrics& aFrameMetrics)
{
CSSRect compositionBounds = aFrameMetrics.CalculateCompositedRectInCssPixels();
aFrameMetrics.mDisplayPort.x = (compositionBounds.width - aFrameMetrics.mDisplayPort.width) / 2;
aFrameMetrics.mDisplayPort.y = (compositionBounds.height - aFrameMetrics.mDisplayPort.height) / 2;
}
static CSSPoint
ScrollFrameTo(nsIScrollableFrame* aFrame, const CSSPoint& aPoint, bool& aSuccessOut)
{
aSuccessOut = false;
if (!aFrame) {
return CSSPoint();
}
@ -100,6 +110,7 @@ ScrollFrameTo(nsIScrollableFrame* aFrame, const CSSPoint& aPoint)
if (!aFrame->IsProcessingAsyncScroll() &&
(!aFrame->OriginOfLastScroll() || aFrame->OriginOfLastScroll() == nsGkAtoms::apz)) {
aFrame->ScrollToCSSPixelsApproximate(aPoint, nsGkAtoms::apz);
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
@ -129,12 +140,23 @@ APZCCallbackHelper::UpdateRootFrame(nsIDOMWindowUtils* aUtils,
// Scroll the window to the desired spot
nsIScrollableFrame* sf = nsLayoutUtils::FindScrollableFrameFor(aMetrics.mScrollId);
CSSPoint actualScrollOffset = ScrollFrameTo(sf, aMetrics.mScrollOffset);
bool scrollUpdated = false;
CSSPoint actualScrollOffset = ScrollFrameTo(sf, aMetrics.mScrollOffset, scrollUpdated);
// Correct the display port due to the difference between mScrollOffset and the
// actual scroll offset, possibly align it to tile boundaries (if tiled layers are
// enabled), and clamp it to the scrollable rect.
MaybeAlignAndClampDisplayPort(aMetrics, actualScrollOffset);
if (scrollUpdated) {
// Correct the display port due to the difference between mScrollOffset and the
// actual scroll offset, possibly align it to tile boundaries (if tiled layers are
// enabled), and clamp it to the scrollable rect.
MaybeAlignAndClampDisplayPort(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.mScrollOffset = actualScrollOffset;
// The mZoom variable on the frame metrics stores the CSS-to-screen scale for this
@ -187,11 +209,16 @@ APZCCallbackHelper::UpdateSubFrame(nsIContent* aContent,
// be scrolled, so here we only have to set the scroll position and displayport.
nsIScrollableFrame* sf = nsLayoutUtils::FindScrollableFrameFor(aMetrics.mScrollId);
CSSPoint actualScrollOffset = ScrollFrameTo(sf, aMetrics.mScrollOffset);
bool scrollUpdated = false;
CSSPoint actualScrollOffset = ScrollFrameTo(sf, aMetrics.mScrollOffset, scrollUpdated);
nsCOMPtr<nsIDOMElement> element = do_QueryInterface(aContent);
if (element) {
MaybeAlignAndClampDisplayPort(aMetrics, actualScrollOffset);
if (scrollUpdated) {
MaybeAlignAndClampDisplayPort(aMetrics, actualScrollOffset);
} else {
RecenterDisplayPort(aMetrics);
}
utils->SetDisplayPortForElement(aMetrics.mDisplayPort.x,
aMetrics.mDisplayPort.y,
aMetrics.mDisplayPort.width,