Bug 1665323. Make sure the visual viewport offset always takes on valid values. r=kats

The problems that it causes that are referred to in the patch is that we use the vvoffset and GetScrollRangeForUserInputEvents to compute the scrollbar cur, min, and max attributes. If we have a non-zero vvoffset when we are zooomed backed out, GetScrollRangeForUserInputEvents will be a zero range and so the cur attribute (non-zero)  will be larger than the max attribute (0).

This then causes nsSliderFrame::AttributeChanged to call ScrollByWhole at

https://searchfox.org/mozilla-central/rev/30e70f2fe80c97bfbfcd975e68538cefd7f58b2a/layout/xul/nsSliderFrame.cpp#204

Which we definitely do not want.

Differential Revision: https://phabricator.services.mozilla.com/D90372
This commit is contained in:
Timothy Nikkel 2020-09-24 02:08:07 +00:00
parent 213122103c
commit 093f97fd96
2 changed files with 40 additions and 7 deletions

View File

@ -11217,22 +11217,33 @@ void PresShell::ResetVisualViewportSize() {
bool PresShell::SetVisualViewportOffset(const nsPoint& aScrollOffset,
const nsPoint& aPrevLayoutScrollPos) {
nsPoint newOffset = aScrollOffset;
nsIScrollableFrame* rootScrollFrame = GetRootScrollFrameAsScrollable();
if (rootScrollFrame) {
// See the comment in nsHTMLScrollFrame::Reflow above the call to
// SetVisualViewportOffset for why we need to do this.
nsRect scrollRange = rootScrollFrame->GetScrollRangeForUserInputEvents();
if (!scrollRange.Contains(newOffset)) {
newOffset.x = std::min(newOffset.x, scrollRange.XMost());
newOffset.x = std::max(newOffset.x, scrollRange.x);
newOffset.y = std::min(newOffset.y, scrollRange.YMost());
newOffset.y = std::max(newOffset.y, scrollRange.y);
}
}
nsPoint prevOffset = GetVisualViewportOffset();
if (prevOffset == aScrollOffset) {
if (prevOffset == newOffset) {
return false;
}
mVisualViewportOffset = Some(aScrollOffset);
mVisualViewportOffset = Some(newOffset);
if (auto* window = nsGlobalWindowInner::Cast(mDocument->GetInnerWindow())) {
window->VisualViewport()->PostScrollEvent(prevOffset, aPrevLayoutScrollPos);
}
if (IsVisualViewportSizeSet()) {
if (nsIScrollableFrame* rootScrollFrame =
GetRootScrollFrameAsScrollable()) {
rootScrollFrame->Anchor()->UserScrolled();
}
if (IsVisualViewportSizeSet() && rootScrollFrame) {
rootScrollFrame->Anchor()->UserScrolled();
}
if (gfxPlatform::UseDesktopZoomingScrollbars()) {

View File

@ -1348,6 +1348,28 @@ void nsHTMLScrollFrame::Reflow(nsPresContext* aPresContext,
}
}
// Note that we need to do this after the
// UpdateVisualViewportSizeForPotentialScrollbarChange call above because that
// is what updates the visual viewport size and we need it to be up to date.
if (mHelper.mIsRoot && !mHelper.UsesOverlayScrollbars() &&
(didHaveHScrollbar != state.mShowHScrollbar ||
didHaveVScrollbar != state.mShowVScrollbar ||
didOnlyHScrollbar != mHelper.mOnlyNeedHScrollbarToScrollVVInsideLV ||
didOnlyVScrollbar != mHelper.mOnlyNeedVScrollbarToScrollVVInsideLV)) {
// Removing layout/classic scrollbars can make a previously valid vvoffset
// invalid. For example, if we are zoomed in on an overflow hidden document
// and then zoom back out, when apz reaches the initial resolution (ie 1.0)
// it won't know that we can remove the scrollbars, so the vvoffset can
// validly be upto the width/height of the scrollbars. After we reflow and
// remove the scrollbars the only valid vvoffset is (0,0). We could wait
// until we send the new frame metrics to apz and then have it reply with
// the new corrected vvoffset but having an inconsistent vvoffset causes
// problems so we re-set the vvoffset here, SetVisualViewportOffset will
// correct it.
PresShell()->SetVisualViewportOffset(GetVisualViewportOffset(),
GetScrollPosition());
}
aDesiredSize.SetOverflowAreasToDesiredBounds();
mHelper.UpdateSticky();