Bug 1669861 - Use the visual scroll offset consistently for DisplayPortMargins computations. r=kats

Even when the margins don't come from APZ, they are relative to
the visual viewport, and for the RCD-RSF there may be an offset
between the visual and layout viewports that they should be
translated by.

Bug 1669982 modified the call site in
CalculateAndSetDisplayPortMargins() to do this. This patch
refactors things such that all setters of the display port
do this if appropriate.

Differential Revision: https://phabricator.services.mozilla.com/D93428
This commit is contained in:
Botond Ballo 2020-10-28 22:13:14 +00:00
parent 2f62453729
commit 2c7ab6e957
5 changed files with 84 additions and 40 deletions

View File

@ -531,7 +531,7 @@ nsDOMWindowUtils::SetDisplayPortMarginsForElement(
DisplayPortUtils::SetDisplayPortMargins(
aElement, presShell,
DisplayPortMargins::WithNoAdjustment(displayportMargins), aPriority);
DisplayPortMargins::ForContent(aElement, displayportMargins), aPriority);
return NS_OK;
}

View File

@ -174,8 +174,9 @@ static DisplayPortMargins ScrollFrame(nsIContent* aContent,
// re-get it.
sf = nsLayoutUtils::FindScrollableFrameFor(aRequest.GetScrollId());
bool scrollUpdated = false;
auto displayPortMargins =
DisplayPortMargins::WithNoAdjustment(aRequest.GetDisplayPortMargins());
auto displayPortMargins = DisplayPortMargins::ForScrollFrame(
sf, aRequest.GetDisplayPortMargins(),
Some(aRequest.DisplayportPixelsPerCSSPixel()));
CSSPoint apzScrollOffset = aRequest.GetVisualScrollOffset();
CSSPoint actualScrollOffset = ScrollFrameTo(sf, aRequest, scrollUpdated);
CSSPoint scrollDelta = apzScrollOffset - actualScrollOffset;
@ -217,8 +218,9 @@ static DisplayPortMargins ScrollFrame(nsIContent* aContent,
// 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.
displayPortMargins = DisplayPortMargins::WithNoAdjustment(
RecenterDisplayPort(aRequest.GetDisplayPortMargins()));
displayPortMargins = DisplayPortMargins::ForScrollFrame(
sf, RecenterDisplayPort(aRequest.GetDisplayPortMargins()),
Some(aRequest.DisplayportPixelsPerCSSPixel()));
}
// APZ transforms inputs assuming we applied the exact scroll offset it
@ -438,8 +440,8 @@ void APZCCallbackHelper::InitializeRootDisplayport(PresShell* aPresShell) {
DisplayPortUtils::SetDisplayPortBaseIfNotSet(content, baseRect);
// Note that we also set the base rect that goes with these margins in
// nsRootBoxFrame::BuildDisplayList.
DisplayPortUtils::SetDisplayPortMargins(content, aPresShell,
DisplayPortMargins::Empty(), 0);
DisplayPortUtils::SetDisplayPortMargins(
content, aPresShell, DisplayPortMargins::Empty(content), 0);
DisplayPortUtils::SetZeroMarginDisplayPortOnAsyncScrollableAncestors(
content->GetPrimaryFrame());
}

View File

@ -47,13 +47,55 @@ DisplayPortMargins DisplayPortMargins::WithAdjustment(
return DisplayPortMargins{aMargins, aVisualOffset, aLayoutOffset, aScale};
}
CSSToScreenScale2D ComputeDisplayportScale(nsIScrollableFrame* aScrollFrame) {
// The calculation here is equivalent to
// CalculateBasicFrameMetrics(aScrollFrame).DisplayportPixelsPerCSSPixel(),
// but we don't calculate the entire frame metrics.
if (!aScrollFrame) {
return CSSToScreenScale2D(1.0, 1.0);
}
nsIFrame* frame = do_QueryFrame(aScrollFrame);
MOZ_ASSERT(frame);
nsPresContext* presContext = frame->PresContext();
PresShell* presShell = presContext->PresShell();
return presContext->CSSToDevPixelScale() *
LayoutDeviceToLayerScale2D(
presShell->GetCumulativeResolution() *
nsLayoutUtils::GetTransformToAncestorScale(frame)) *
LayerToScreenScale2D(1.0, 1.0);
}
/* static */
DisplayPortMargins DisplayPortMargins::WithNoAdjustment(
const ScreenMargin& aMargins) {
// Use values such that GetRelativeToLayoutViewport() will just return
// mMargins.
return WithAdjustment(aMargins, CSSPoint(), CSSPoint(),
CSSToScreenScale2D(1.0, 1.0));
DisplayPortMargins DisplayPortMargins::ForScrollFrame(
nsIScrollableFrame* aScrollFrame, const ScreenMargin& aMargins,
const Maybe<CSSToScreenScale2D>& aScale) {
CSSPoint visualOffset;
CSSPoint layoutOffset;
if (aScrollFrame) {
nsIFrame* scrollFrame = do_QueryFrame(aScrollFrame);
PresShell* presShell = scrollFrame->PresShell();
layoutOffset = CSSPoint::FromAppUnits(aScrollFrame->GetScrollPosition());
if (aScrollFrame->IsRootScrollFrameOfDocument() &&
presShell->IsVisualViewportOffsetSet()) {
visualOffset =
CSSPoint::FromAppUnits(presShell->GetVisualViewportOffset());
} else {
visualOffset = layoutOffset;
}
}
return DisplayPortMargins{aMargins, visualOffset, layoutOffset,
aScale.valueOrFrom([&] {
return ComputeDisplayportScale(aScrollFrame);
})};
}
/* static */
DisplayPortMargins DisplayPortMargins::ForContent(
nsIContent* aContent, const ScreenMargin& aMargins) {
return ForScrollFrame(
aContent ? nsLayoutUtils::FindScrollableFrameFor(aContent) : nullptr,
aMargins, Nothing());
}
ScreenMargin DisplayPortMargins::GetRelativeToLayoutViewport(
@ -507,8 +549,9 @@ static bool GetDisplayPortImpl(nsIContent* aContent, nsRect* aResult,
result = GetDisplayPortFromRectData(aContent, rectData, aMultiplier);
} else if (isDisplayportSuppressed ||
nsLayoutUtils::ShouldDisableApzForElement(aContent)) {
DisplayPortMarginsPropertyData noMargins(DisplayPortMargins::Empty(), 1,
/*painted=*/false);
DisplayPortMarginsPropertyData noMargins(
DisplayPortMargins::Empty(aContent), 1,
/*painted=*/false);
result = GetDisplayPortFromMarginsData(aContent, &noMargins, aMultiplier,
aOptions);
} else {
@ -859,24 +902,9 @@ bool DisplayPortUtils::CalculateAndSetDisplayPortMargins(
metrics, ParentLayerPoint(0.0f, 0.0f));
PresShell* presShell = frame->PresContext()->GetPresShell();
DisplayPortMargins margins;
if (metrics.IsRootContent()) {
// Make sure to preserve the layout vs visual adjustment because we
// just computed displayportMargins using the visual scroll offset above,
// and that may be different than the layout scroll offset.
margins = DisplayPortMargins::WithAdjustment(
displayportMargins, metrics.GetVisualScrollOffset(),
metrics.GetLayoutScrollOffset(),
metrics.DisplayportPixelsPerCSSPixel());
} else {
// For non-root content the visual scroll offset should always be
// the same as the layout scroll offset. We could just take the code
// path above, but there's some value in being able to distinguish
// the two cases when debugging.
MOZ_ASSERT(metrics.GetVisualScrollOffset() ==
metrics.GetLayoutScrollOffset());
margins = DisplayPortMargins::WithNoAdjustment(displayportMargins);
}
DisplayPortMargins margins = DisplayPortMargins::ForScrollFrame(
aScrollFrame, displayportMargins,
Some(metrics.DisplayportPixelsPerCSSPixel()));
return SetDisplayPortMargins(content, presShell, margins, 0, aRepaintMode);
}
@ -945,7 +973,7 @@ void DisplayPortUtils::SetZeroMarginDisplayPortOnAsyncScrollableAncestors(
if (nsLayoutUtils::AsyncPanZoomEnabled(frame) &&
!HasDisplayPort(frame->GetContent())) {
SetDisplayPortMargins(frame->GetContent(), frame->PresShell(),
DisplayPortMargins::Empty(), 0,
DisplayPortMargins::Empty(frame->GetContent()), 0,
RepaintMode::Repaint);
}
}

View File

@ -97,9 +97,23 @@ struct DisplayPortMargins {
const CSSPoint& aLayoutOffset,
const CSSToScreenScale2D& aScale);
static DisplayPortMargins WithNoAdjustment(const ScreenMargin& aMargins);
// Create displayport port margins for the given scroll frame.
// This is for use in cases where we don't have async scroll information from
// APZ to use to adjust the margins. The visual and layout offset are set
// based on the main thread's view of them. If a scale isn't provided, one
// is computed based on the main thread's knowledge.
static DisplayPortMargins ForScrollFrame(
nsIScrollableFrame* aScrollFrame, const ScreenMargin& aMargins,
const Maybe<CSSToScreenScale2D>& aScale = Nothing());
static DisplayPortMargins Empty() { return WithNoAdjustment(ScreenMargin()); }
// Convenience version of the above that takes a content element.
static DisplayPortMargins ForContent(nsIContent* aContent,
const ScreenMargin& aMargins);
// Another convenience version that sets empty margins.
static DisplayPortMargins Empty(nsIContent* aContent) {
return ForContent(aContent, ScreenMargin());
}
// Get the margins relative to the layout viewport.
// |aGeometryType| tells us whether the margins are being queried for the

View File

@ -2246,9 +2246,9 @@ ScrollFrameHelper::ScrollFrameHelper(nsContainerFrame* aOuter, bool aIsRoot)
// If we have tiling but no APZ, then set a 0-margin display port on
// active scroll containers so that we paint by whole tile increments
// when scrolling.
DisplayPortUtils::SetDisplayPortMargins(mOuter->GetContent(),
mOuter->PresShell(),
DisplayPortMargins::Empty(), 0);
DisplayPortUtils::SetDisplayPortMargins(
mOuter->GetContent(), mOuter->PresShell(),
DisplayPortMargins::Empty(mOuter->GetContent()), 0);
DisplayPortUtils::SetZeroMarginDisplayPortOnAsyncScrollableAncestors(
mOuter);
}
@ -3945,7 +3945,7 @@ void ScrollFrameHelper::BuildDisplayList(nsDisplayListBuilder* aBuilder,
// to be disabled on the next paint.
DisplayPortUtils::SetDisplayPortMargins(
mOuter->GetContent(), mOuter->PresShell(),
DisplayPortMargins::Empty(), 0,
DisplayPortMargins::Empty(mOuter->GetContent()), 0,
DisplayPortUtils::RepaintMode::DoNotRepaint);
// Call DecideScrollableLayer to recompute mWillBuildScrollableLayer
// and recompute the current animated geometry root if needed. It's