Commit 4b22730a authored by Emilio Cobos Álvarez's avatar Emilio Cobos Álvarez
Browse files

Bug 1642922 - Tweak scroll-padding implementation to also account for visibility. r=hiro, a=RyanVM

The previous implementation made us think that stuff was visible when in
fact it was not.

Differential Revision: https://phabricator.services.mozilla.com/D79345
parent 3ff0b67a
......@@ -25,6 +25,9 @@
width: 100%;
background: green;
}
.almost-full-padding {
height: calc(100vh - 200px);
}
.padding {
height: 100vh;
}
......@@ -32,6 +35,8 @@
<div id="fixed-header"></div>
<div class="padding"></div>
<input>
<div class="almost-full-padding"></div>
<input>
<div class="padding"></div>
<input id="end">
<div class="padding"></div>
......
......@@ -3314,18 +3314,20 @@ static void AccumulateFrameBounds(nsIFrame* aContainerFrame, nsIFrame* aFrame,
static bool ComputeNeedToScroll(WhenToScroll aWhenToScroll, nscoord aLineSize,
nscoord aRectMin, nscoord aRectMax,
nscoord aViewMin, nscoord aViewMax) {
// See how the rect should be positioned vertically
if (WhenToScroll::Always == aWhenToScroll) {
// The caller wants the frame as visible as possible
return true;
} else if (WhenToScroll::IfNotVisible == aWhenToScroll) {
// Scroll only if no part of the frame is visible in this view
return aRectMax - aLineSize <= aViewMin || aRectMin + aLineSize >= aViewMax;
} else if (WhenToScroll::IfNotFullyVisible == aWhenToScroll) {
// Scroll only if part of the frame is hidden and more can fit in view
return !(aRectMin >= aViewMin && aRectMax <= aViewMax) &&
std::min(aViewMax, aRectMax) - std::max(aRectMin, aViewMin) <
aViewMax - aViewMin;
// See how the rect should be positioned in a given axis.
switch (aWhenToScroll) {
case WhenToScroll::Always:
// The caller wants the frame as visible as possible
return true;
case WhenToScroll::IfNotVisible:
// Scroll only if no part of the frame is visible in this view.
return aRectMax - aLineSize <= aViewMin ||
aRectMin + aLineSize >= aViewMax;
case WhenToScroll::IfNotFullyVisible:
// Scroll only if part of the frame is hidden and more can fit in view
return !(aRectMin >= aViewMin && aRectMax <= aViewMax) &&
std::min(aViewMax, aRectMax) - std::max(aRectMin, aViewMin) <
aViewMax - aViewMin;
}
return false;
}
......@@ -3368,7 +3370,20 @@ static void ScrollToShowRect(nsIScrollableFrame* aFrameAsScrollable,
const nsRect& aRect, ScrollAxis aVertical,
ScrollAxis aHorizontal, ScrollFlags aScrollFlags) {
nsPoint scrollPt = aFrameAsScrollable->GetVisualViewportOffset();
nsRect visibleRect(scrollPt, aFrameAsScrollable->GetVisualViewportSize());
const nsPoint originalScrollPt = scrollPt;
const nsRect visibleRect(scrollPt,
aFrameAsScrollable->GetVisualViewportSize());
const nsMargin scrollPadding =
(aScrollFlags & ScrollFlags::IgnoreMarginAndPadding)
? nsMargin()
: aFrameAsScrollable->GetScrollPadding();
const nsRect rectToScrollIntoView = [&] {
nsRect r(aRect);
r.Inflate(scrollPadding);
return r.Intersect(aFrameAsScrollable->GetScrolledRect());
}();
nsSize lineSize;
// Don't call GetLineScrollAmount unless we actually need it. Not only
......@@ -3382,7 +3397,6 @@ static void ScrollToShowRect(nsIScrollableFrame* aFrameAsScrollable,
}
ScrollStyles ss = aFrameAsScrollable->GetScrollStyles();
nsRect allowedRange(scrollPt, nsSize(0, 0));
bool needToScroll = false;
uint32_t directions = aFrameAsScrollable->GetAvailableScrollingDirections();
if (((aScrollFlags & ScrollFlags::ScrollOverflowHidden) ||
......@@ -3390,14 +3404,14 @@ static void ScrollToShowRect(nsIScrollableFrame* aFrameAsScrollable,
(!aVertical.mOnlyIfPerceivedScrollableDirection ||
(directions & nsIScrollableFrame::VERTICAL))) {
if (ComputeNeedToScroll(aVertical.mWhenToScroll, lineSize.height, aRect.y,
aRect.YMost(), visibleRect.y,
visibleRect.YMost())) {
aRect.YMost(), visibleRect.y + scrollPadding.top,
visibleRect.YMost() - scrollPadding.bottom)) {
nscoord maxHeight;
scrollPt.y = ComputeWhereToScroll(
aVertical.mWhereToScroll, scrollPt.y, aRect.y, aRect.YMost(),
aVertical.mWhereToScroll, scrollPt.y, rectToScrollIntoView.y,
rectToScrollIntoView.YMost(),
visibleRect.y, visibleRect.YMost(), &allowedRange.y, &maxHeight);
allowedRange.height = maxHeight - allowedRange.y;
needToScroll = true;
}
}
......@@ -3406,47 +3420,49 @@ static void ScrollToShowRect(nsIScrollableFrame* aFrameAsScrollable,
(!aHorizontal.mOnlyIfPerceivedScrollableDirection ||
(directions & nsIScrollableFrame::HORIZONTAL))) {
if (ComputeNeedToScroll(aHorizontal.mWhenToScroll, lineSize.width, aRect.x,
aRect.XMost(), visibleRect.x,
visibleRect.XMost())) {
aRect.XMost(), visibleRect.x + scrollPadding.left,
visibleRect.XMost() - scrollPadding.right)) {
nscoord maxWidth;
scrollPt.x = ComputeWhereToScroll(
aHorizontal.mWhereToScroll, scrollPt.x, aRect.x, aRect.XMost(),
visibleRect.x, visibleRect.XMost(), &allowedRange.x, &maxWidth);
aHorizontal.mWhereToScroll, scrollPt.x, rectToScrollIntoView.x,
rectToScrollIntoView.XMost(), visibleRect.x, visibleRect.XMost(),
&allowedRange.x, &maxWidth);
allowedRange.width = maxWidth - allowedRange.x;
needToScroll = true;
}
}
// If we don't need to scroll, then don't try since it might cancel
// a current smooth scroll operation.
if (needToScroll) {
ScrollMode scrollMode = ScrollMode::Instant;
bool autoBehaviorIsSmooth = aFrameAsScrollable->IsSmoothScroll();
bool smoothScroll = (aScrollFlags & ScrollFlags::ScrollSmooth) ||
((aScrollFlags & ScrollFlags::ScrollSmoothAuto) &&
autoBehaviorIsSmooth);
if (StaticPrefs::layout_css_scroll_behavior_enabled() && smoothScroll) {
scrollMode = ScrollMode::SmoothMsd;
}
nsIFrame* frame = do_QueryFrame(aFrameAsScrollable);
AutoWeakFrame weakFrame(frame);
aFrameAsScrollable->ScrollTo(scrollPt, scrollMode, &allowedRange,
aScrollFlags & ScrollFlags::ScrollSnap
? nsIScrollbarMediator::ENABLE_SNAP
: nsIScrollbarMediator::DISABLE_SNAP);
if (!weakFrame.IsAlive()) {
return;
}
if (scrollPt == originalScrollPt) {
return;
}
// If this is the RCD-RSF, also call ScrollToVisual() since we want to
// scroll the rect into view visually, and that may require scrolling
// the visual viewport in scenarios where there is not enough layout
// scroll range.
if (aFrameAsScrollable->IsRootScrollFrameOfDocument() &&
frame->PresShell()->GetPresContext()->IsRootContentDocument()) {
frame->PresShell()->ScrollToVisual(scrollPt, FrameMetrics::eMainThread,
scrollMode);
}
ScrollMode scrollMode = ScrollMode::Instant;
bool autoBehaviorIsSmooth = aFrameAsScrollable->IsSmoothScroll();
bool smoothScroll = (aScrollFlags & ScrollFlags::ScrollSmooth) ||
((aScrollFlags & ScrollFlags::ScrollSmoothAuto) &&
autoBehaviorIsSmooth);
if (StaticPrefs::layout_css_scroll_behavior_enabled() && smoothScroll) {
scrollMode = ScrollMode::SmoothMsd;
}
nsIFrame* frame = do_QueryFrame(aFrameAsScrollable);
AutoWeakFrame weakFrame(frame);
aFrameAsScrollable->ScrollTo(scrollPt, scrollMode, &allowedRange,
aScrollFlags & ScrollFlags::ScrollSnap
? nsIScrollbarMediator::ENABLE_SNAP
: nsIScrollbarMediator::DISABLE_SNAP);
if (!weakFrame.IsAlive()) {
return;
}
// If this is the RCD-RSF, also call ScrollToVisual() since we want to
// scroll the rect into view visually, and that may require scrolling
// the visual viewport in scenarios where there is not enough layout
// scroll range.
if (aFrameAsScrollable->IsRootScrollFrameOfDocument() &&
frame->PresShell()->GetPresContext()->IsRootContentDocument()) {
frame->PresShell()->ScrollToVisual(scrollPt, FrameMetrics::eMainThread,
scrollMode);
}
}
......@@ -3605,11 +3621,6 @@ bool PresShell::ScrollFrameRectIntoView(nsIFrame* aFrame, const nsRect& aRect,
}
targetRect -= sf->GetScrolledFrame()->GetPosition();
if (!(aScrollFlags & ScrollFlags::IgnoreMarginAndPadding)) {
nsMargin scrollPadding = sf->GetScrollPadding();
targetRect.Inflate(scrollPadding);
targetRect = targetRect.Intersect(sf->GetScrolledRect());
}
{
AutoWeakFrame wf(container);
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment