зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1650502 - Plumb whether an async APZ animation is in progress via RepaintRequest. r=botond
And store that information in the scroll frame for the purposes of avoiding scroll anchoring and scroll restoration. Differential Revision: https://phabricator.services.mozilla.com/D85157
This commit is contained in:
Родитель
fff8c6763f
Коммит
f08a5f293b
|
@ -57,10 +57,12 @@ struct RepaintRequest {
|
|||
mPaintRequestTime(),
|
||||
mScrollUpdateType(eNone),
|
||||
mIsRootContent(false),
|
||||
mIsAnimationInProgress(false),
|
||||
mIsScrollInfoLayer(false) {}
|
||||
|
||||
RepaintRequest(const FrameMetrics& aOther,
|
||||
const ScrollOffsetUpdateType aScrollUpdateType)
|
||||
const ScrollOffsetUpdateType aScrollUpdateType,
|
||||
bool aIsAnimationInProgress)
|
||||
: mScrollId(aOther.GetScrollId()),
|
||||
mPresShellResolution(aOther.GetPresShellResolution()),
|
||||
mCompositionBounds(aOther.GetCompositionBounds()),
|
||||
|
@ -76,6 +78,7 @@ struct RepaintRequest {
|
|||
mPaintRequestTime(aOther.GetPaintRequestTime()),
|
||||
mScrollUpdateType(aScrollUpdateType),
|
||||
mIsRootContent(aOther.IsRootContent()),
|
||||
mIsAnimationInProgress(aIsAnimationInProgress),
|
||||
mIsScrollInfoLayer(aOther.IsScrollInfoLayer()) {}
|
||||
|
||||
// Default copy ctor and operator= are fine
|
||||
|
@ -97,6 +100,7 @@ struct RepaintRequest {
|
|||
mPaintRequestTime == aOther.mPaintRequestTime &&
|
||||
mScrollUpdateType == aOther.mScrollUpdateType &&
|
||||
mIsRootContent == aOther.mIsRootContent &&
|
||||
mIsAnimationInProgress == aOther.mIsAnimationInProgress &&
|
||||
mIsScrollInfoLayer == aOther.mIsScrollInfoLayer;
|
||||
}
|
||||
|
||||
|
@ -147,6 +151,8 @@ struct RepaintRequest {
|
|||
return mDevPixelsPerCSSPixel;
|
||||
}
|
||||
|
||||
bool IsAnimationInProgress() const { return mIsAnimationInProgress; }
|
||||
|
||||
bool IsRootContent() const { return mIsRootContent; }
|
||||
|
||||
const CSSPoint& GetScrollOffset() const { return mScrollOffset; }
|
||||
|
@ -180,6 +186,10 @@ struct RepaintRequest {
|
|||
bool IsScrollInfoLayer() const { return mIsScrollInfoLayer; }
|
||||
|
||||
protected:
|
||||
void SetIsAnimationInProgress(bool aInProgress) {
|
||||
mIsAnimationInProgress = aInProgress;
|
||||
}
|
||||
|
||||
void SetIsRootContent(bool aIsRootContent) {
|
||||
mIsRootContent = aIsRootContent;
|
||||
}
|
||||
|
@ -280,6 +290,9 @@ struct RepaintRequest {
|
|||
// Whether or not this is the root scroll frame for the root content document.
|
||||
bool mIsRootContent : 1;
|
||||
|
||||
// Whether or not we are in the middle of a scroll animation.
|
||||
bool mIsAnimationInProgress : 1;
|
||||
|
||||
// True if this scroll frame is a scroll info layer. A scroll info layer is
|
||||
// not layerized and its content cannot be truly async-scrolled, but its
|
||||
// metrics are still sent to and updated by the compositor, with the updates
|
||||
|
|
|
@ -3982,7 +3982,8 @@ void AsyncPanZoomController::RequestContentRepaint(
|
|||
}
|
||||
MOZ_ASSERT(controller->IsRepaintThread());
|
||||
|
||||
RepaintRequest request(aFrameMetrics, aUpdateType);
|
||||
const bool isAnimationInProgress = !!mAnimation;
|
||||
RepaintRequest request(aFrameMetrics, aUpdateType, isAnimationInProgress);
|
||||
|
||||
// If we're trying to paint what we already think is painted, discard this
|
||||
// request since it's a pointless paint.
|
||||
|
@ -3998,7 +3999,9 @@ void AsyncPanZoomController::RequestContentRepaint(
|
|||
request.GetScrollGeneration() ==
|
||||
mLastPaintRequestMetrics.GetScrollGeneration() &&
|
||||
request.GetScrollUpdateType() ==
|
||||
mLastPaintRequestMetrics.GetScrollUpdateType()) {
|
||||
mLastPaintRequestMetrics.GetScrollUpdateType() &&
|
||||
request.IsAnimationInProgress() ==
|
||||
mLastPaintRequestMetrics.IsAnimationInProgress()) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -164,7 +164,8 @@ static ScreenMargin ScrollFrame(nsIContent* aContent,
|
|||
nsIScrollableFrame* sf =
|
||||
nsLayoutUtils::FindScrollableFrameFor(aRequest.GetScrollId());
|
||||
if (sf) {
|
||||
sf->ResetScrollInfoIfGeneration(aRequest.GetScrollGeneration());
|
||||
sf->ResetScrollInfoIfNeeded(aRequest.GetScrollGeneration(),
|
||||
aRequest.IsAnimationInProgress());
|
||||
sf->SetScrollableByAPZ(!aRequest.IsScrollInfoLayer());
|
||||
if (sf->IsRootScrollFrameOfDocument()) {
|
||||
if (!APZCCallbackHelper::IsScrollInProgress(sf)) {
|
||||
|
@ -834,10 +835,10 @@ void APZCCallbackHelper::NotifyFlushComplete(PresShell* aPresShell) {
|
|||
|
||||
/* static */
|
||||
bool APZCCallbackHelper::IsScrollInProgress(nsIScrollableFrame* aFrame) {
|
||||
return aFrame->IsProcessingAsyncScroll() ||
|
||||
nsLayoutUtils::CanScrollOriginClobberApz(aFrame->LastScrollOrigin()) ||
|
||||
aFrame->LastSmoothScrollOrigin() != ScrollOrigin::None ||
|
||||
aFrame->GetRelativeOffset().isSome();
|
||||
using IncludeApzAnimation = nsIScrollableFrame::IncludeApzAnimation;
|
||||
|
||||
return aFrame->IsScrollAnimating(IncludeApzAnimation::No) ||
|
||||
nsLayoutUtils::CanScrollOriginClobberApz(aFrame->LastScrollOrigin());
|
||||
}
|
||||
|
||||
/* static */
|
||||
|
|
|
@ -179,8 +179,11 @@ class APZCCallbackHelper {
|
|||
ScreenPoint aScrollDelta);
|
||||
|
||||
/*
|
||||
* Check if the scrollable frame is currently in the middle of an async
|
||||
* or smooth scroll. We want to discard certain scroll input if this is
|
||||
* Check if the scrollable frame is currently in the middle of a main thread
|
||||
* async or smooth scroll, or has already requested some other apz scroll that
|
||||
* hasn't been acknowledged by apz.
|
||||
*
|
||||
* We want to discard apz updates to the main-thread scroll offset if this is
|
||||
* true to prevent clobbering higher priority origins.
|
||||
*/
|
||||
static bool IsScrollInProgress(nsIScrollableFrame* aFrame);
|
||||
|
|
|
@ -278,6 +278,7 @@ struct ParamTraits<mozilla::layers::RepaintRequest>
|
|||
WriteParam(aMsg, aParam.mPaintRequestTime);
|
||||
WriteParam(aMsg, aParam.mScrollUpdateType);
|
||||
WriteParam(aMsg, aParam.mIsRootContent);
|
||||
WriteParam(aMsg, aParam.mIsAnimationInProgress);
|
||||
WriteParam(aMsg, aParam.mIsScrollInfoLayer);
|
||||
}
|
||||
|
||||
|
@ -299,6 +300,8 @@ struct ParamTraits<mozilla::layers::RepaintRequest>
|
|||
ReadParam(aMsg, aIter, &aResult->mScrollUpdateType) &&
|
||||
ReadBoolForBitfield(aMsg, aIter, aResult,
|
||||
¶mType::SetIsRootContent) &&
|
||||
ReadBoolForBitfield(aMsg, aIter, aResult,
|
||||
¶mType::SetIsAnimationInProgress) &&
|
||||
ReadBoolForBitfield(aMsg, aIter, aResult,
|
||||
¶mType::SetIsScrollInfoLayer));
|
||||
}
|
||||
|
|
|
@ -418,19 +418,17 @@ void ScrollAnchorContainer::ApplyAdjustments() {
|
|||
if (!mAnchorNode || mAnchorNodeIsDirty || mDisabled ||
|
||||
mScrollFrame->HasPendingScrollRestoration() ||
|
||||
mScrollFrame->IsProcessingScrollEvent() ||
|
||||
mScrollFrame->IsProcessingAsyncScroll() ||
|
||||
mScrollFrame->mApzSmoothScrollDestination.isSome() ||
|
||||
mScrollFrame->IsScrollAnimating() ||
|
||||
mScrollFrame->GetScrollPosition() == nsPoint()) {
|
||||
ANCHOR_LOG(
|
||||
"Ignoring post-reflow (anchor=%p, dirty=%d, disabled=%d, "
|
||||
"pendingRestoration=%d, scrollevent=%d, asyncScroll=%d, "
|
||||
"apzSmoothDestination=%d, zeroScrollPos=%d pendingSuppression=%d, "
|
||||
"pendingRestoration=%d, scrollevent=%d, animating=%d, "
|
||||
"zeroScrollPos=%d pendingSuppression=%d, "
|
||||
"container=%p).\n",
|
||||
mAnchorNode, mAnchorNodeIsDirty, mDisabled,
|
||||
mScrollFrame->HasPendingScrollRestoration(),
|
||||
mScrollFrame->IsProcessingScrollEvent(),
|
||||
mScrollFrame->IsProcessingAsyncScroll(),
|
||||
mScrollFrame->mApzSmoothScrollDestination.isSome(),
|
||||
mScrollFrame->IsScrollAnimating(),
|
||||
mScrollFrame->GetScrollPosition() == nsPoint(),
|
||||
mSuppressAnchorAdjustment, this);
|
||||
if (mSuppressAnchorAdjustment) {
|
||||
|
|
|
@ -2184,6 +2184,7 @@ ScrollFrameHelper::ScrollFrameHelper(nsContainerFrame* aOuter, bool aIsRoot)
|
|||
mIsUsingMinimumScaleSize(false),
|
||||
mMinimumScaleSizeChanged(false),
|
||||
mProcessingScrollEvent(false),
|
||||
mApzAnimationInProgress(false),
|
||||
mVelocityQueue(aOuter->PresContext()) {
|
||||
if (LookAndFeel::GetInt(LookAndFeel::IntID::UseOverlayScrollbars) != 0) {
|
||||
mScrollbarActivity = new ScrollbarActivity(do_QueryFrame(aOuter));
|
||||
|
@ -6185,8 +6186,7 @@ bool ScrollFrameHelper::ReflowFinished() {
|
|||
// do anything.
|
||||
nsPoint currentScrollPos = GetScrollPosition();
|
||||
ScrollToImpl(currentScrollPos, nsRect(currentScrollPos, nsSize(0, 0)));
|
||||
if (!mAsyncScroll && !mAsyncSmoothMSDScroll &&
|
||||
!mApzSmoothScrollDestination) {
|
||||
if (!IsScrollAnimating()) {
|
||||
// We need to have mDestination track the current scroll position,
|
||||
// in case it falls outside the new reflow area. mDestination is used
|
||||
// by ScrollBy as its starting position.
|
||||
|
@ -6826,6 +6826,16 @@ nscoord ScrollFrameHelper::GetCoordAttribute(nsIFrame* aBox, nsAtom* aAtom,
|
|||
return aDefaultValue;
|
||||
}
|
||||
|
||||
bool ScrollFrameHelper::IsScrollAnimating(
|
||||
IncludeApzAnimation aIncludeApz) const {
|
||||
if (aIncludeApz == IncludeApzAnimation::Yes && IsApzAnimationInProgress()) {
|
||||
return true;
|
||||
}
|
||||
return mAsyncScroll || mAsyncSmoothMSDScroll ||
|
||||
LastSmoothScrollOrigin() != ScrollOrigin::None ||
|
||||
mRelativeOffset.isSome();
|
||||
}
|
||||
|
||||
UniquePtr<PresState> ScrollFrameHelper::SaveState() const {
|
||||
nsIScrollbarMediator* mediator = do_QueryFrame(GetScrolledFrame());
|
||||
if (mediator) {
|
||||
|
@ -6835,10 +6845,8 @@ UniquePtr<PresState> ScrollFrameHelper::SaveState() const {
|
|||
|
||||
// Don't store a scroll state if we never have been scrolled or restored
|
||||
// a previous scroll state, and we're not in the middle of a smooth scroll.
|
||||
bool isInSmoothScroll = IsProcessingAsyncScroll() ||
|
||||
mLastSmoothScrollOrigin != ScrollOrigin::None ||
|
||||
mRelativeOffset.isSome();
|
||||
if (!mHasBeenScrolled && !mDidHistoryRestore && !isInSmoothScroll) {
|
||||
bool isScrollAnimating = IsScrollAnimating(IncludeApzAnimation::No);
|
||||
if (!mHasBeenScrolled && !mDidHistoryRestore && !isScrollAnimating) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
@ -6856,7 +6864,7 @@ UniquePtr<PresState> ScrollFrameHelper::SaveState() const {
|
|||
// effectively dropping it. Note that the mRestorePos will override the
|
||||
// smooth scroll destination if both are present.
|
||||
nsPoint pt = GetLogicalVisualViewportOffset();
|
||||
if (isInSmoothScroll) {
|
||||
if (isScrollAnimating) {
|
||||
pt = mDestination;
|
||||
allowScrollOriginDowngrade = false;
|
||||
}
|
||||
|
|
|
@ -376,9 +376,6 @@ class ScrollFrameHelper : public nsIReflowCallback {
|
|||
return mWillBuildScrollableLayer;
|
||||
}
|
||||
bool IsMaybeScrollingActive() const;
|
||||
bool IsProcessingAsyncScroll() const {
|
||||
return mAsyncScroll != nullptr || mAsyncSmoothMSDScroll != nullptr;
|
||||
}
|
||||
void ResetScrollPositionForLayerPixelAlignment() {
|
||||
mScrollPosForLayerPixelAlignment = GetScrollPosition();
|
||||
}
|
||||
|
@ -463,13 +460,22 @@ class ScrollFrameHelper : public nsIReflowCallback {
|
|||
ScrollOrigin LastSmoothScrollOrigin() const {
|
||||
return mLastSmoothScrollOrigin;
|
||||
}
|
||||
bool IsApzAnimationInProgress() const { return mApzAnimationInProgress; }
|
||||
uint32_t CurrentScrollGeneration() const { return mScrollGeneration; }
|
||||
nsPoint LastScrollDestination() const { return mDestination; }
|
||||
void ResetScrollInfoIfGeneration(uint32_t aGeneration) {
|
||||
|
||||
using IncludeApzAnimation = nsIScrollableFrame::IncludeApzAnimation;
|
||||
bool IsScrollAnimating(IncludeApzAnimation = IncludeApzAnimation::Yes) const;
|
||||
|
||||
void ResetScrollInfoIfNeeded(uint32_t aGeneration,
|
||||
bool aApzAnimationInProgress) {
|
||||
if (aGeneration == mScrollGeneration) {
|
||||
mLastScrollOrigin = ScrollOrigin::NotSpecified;
|
||||
mLastSmoothScrollOrigin = ScrollOrigin::None;
|
||||
}
|
||||
// We can reset this regardless of scroll generation, as this is only set
|
||||
// here, as a response to APZ requesting a repaint.
|
||||
mApzAnimationInProgress = aApzAnimationInProgress;
|
||||
}
|
||||
Maybe<nsPoint> GetRelativeOffset() const { return mRelativeOffset; }
|
||||
bool WantAsyncScroll() const;
|
||||
|
@ -705,6 +711,13 @@ class ScrollFrameHelper : public nsIReflowCallback {
|
|||
// True if we're processing an scroll event.
|
||||
bool mProcessingScrollEvent : 1;
|
||||
|
||||
// Whether an APZ animation is in progress. Note that this is only set to true
|
||||
// when repainted via APZ, which means that there may be a request for an APZ
|
||||
// animation in flight for example, while this is still false. In order to
|
||||
// answer "is an APZ animation in the process of starting or in progress" you
|
||||
// need to check both mLastSmoothScrollOrigin and this bit.
|
||||
bool mApzAnimationInProgress : 1;
|
||||
|
||||
mozilla::layout::ScrollVelocityQueue mVelocityQueue;
|
||||
|
||||
protected:
|
||||
|
@ -1018,9 +1031,6 @@ class nsHTMLScrollFrame : public nsContainerFrame,
|
|||
bool IsMaybeAsynchronouslyScrolled() final {
|
||||
return mHelper.IsMaybeAsynchronouslyScrolled();
|
||||
}
|
||||
bool IsProcessingAsyncScroll() final {
|
||||
return mHelper.IsProcessingAsyncScroll();
|
||||
}
|
||||
void ResetScrollPositionForLayerPixelAlignment() final {
|
||||
mHelper.ResetScrollPositionForLayerPixelAlignment();
|
||||
}
|
||||
|
@ -1037,14 +1047,18 @@ class nsHTMLScrollFrame : public nsContainerFrame,
|
|||
ScrollOrigin LastSmoothScrollOrigin() final {
|
||||
return mHelper.LastSmoothScrollOrigin();
|
||||
}
|
||||
bool IsScrollAnimating(IncludeApzAnimation aIncludeApz) final {
|
||||
return mHelper.IsScrollAnimating(aIncludeApz);
|
||||
}
|
||||
uint32_t CurrentScrollGeneration() final {
|
||||
return mHelper.CurrentScrollGeneration();
|
||||
}
|
||||
nsPoint LastScrollDestination() final {
|
||||
return mHelper.LastScrollDestination();
|
||||
}
|
||||
void ResetScrollInfoIfGeneration(uint32_t aGeneration) final {
|
||||
mHelper.ResetScrollInfoIfGeneration(aGeneration);
|
||||
void ResetScrollInfoIfNeeded(uint32_t aGeneration,
|
||||
bool aApzAnimationInProgress) final {
|
||||
mHelper.ResetScrollInfoIfNeeded(aGeneration, aApzAnimationInProgress);
|
||||
}
|
||||
Maybe<nsPoint> GetRelativeOffset() const final {
|
||||
return mHelper.GetRelativeOffset();
|
||||
|
@ -1493,9 +1507,6 @@ class nsXULScrollFrame final : public nsBoxFrame,
|
|||
bool IsMaybeAsynchronouslyScrolled() final {
|
||||
return mHelper.IsMaybeAsynchronouslyScrolled();
|
||||
}
|
||||
bool IsProcessingAsyncScroll() final {
|
||||
return mHelper.IsProcessingAsyncScroll();
|
||||
}
|
||||
void ResetScrollPositionForLayerPixelAlignment() final {
|
||||
mHelper.ResetScrollPositionForLayerPixelAlignment();
|
||||
}
|
||||
|
@ -1512,14 +1523,18 @@ class nsXULScrollFrame final : public nsBoxFrame,
|
|||
ScrollOrigin LastSmoothScrollOrigin() final {
|
||||
return mHelper.LastSmoothScrollOrigin();
|
||||
}
|
||||
bool IsScrollAnimating(IncludeApzAnimation aIncludeApz) final {
|
||||
return mHelper.IsScrollAnimating(aIncludeApz);
|
||||
}
|
||||
uint32_t CurrentScrollGeneration() final {
|
||||
return mHelper.CurrentScrollGeneration();
|
||||
}
|
||||
nsPoint LastScrollDestination() final {
|
||||
return mHelper.LastScrollDestination();
|
||||
}
|
||||
void ResetScrollInfoIfGeneration(uint32_t aGeneration) final {
|
||||
mHelper.ResetScrollInfoIfGeneration(aGeneration);
|
||||
void ResetScrollInfoIfNeeded(uint32_t aGeneration,
|
||||
bool aApzAnimationInProgress) final {
|
||||
mHelper.ResetScrollInfoIfNeeded(aGeneration, aApzAnimationInProgress);
|
||||
}
|
||||
Maybe<nsPoint> GetRelativeOffset() const final {
|
||||
return mHelper.GetRelativeOffset();
|
||||
|
|
|
@ -380,11 +380,6 @@ class nsIScrollableFrame : public nsIScrollbarMediator {
|
|||
* which means that it can be called during display list building.
|
||||
*/
|
||||
virtual bool IsMaybeScrollingActive() const = 0;
|
||||
/**
|
||||
* Returns true if the scrollframe is currently processing an async
|
||||
* or smooth scroll.
|
||||
*/
|
||||
virtual bool IsProcessingAsyncScroll() = 0;
|
||||
/**
|
||||
* Call this when the layer(s) induced by active scrolling are being
|
||||
* completely redrawn.
|
||||
|
@ -436,6 +431,19 @@ class nsIScrollableFrame : public nsIScrollbarMediator {
|
|||
* compositor, this is set to nullptr to clear the smooth scroll.
|
||||
*/
|
||||
virtual ScrollOrigin LastSmoothScrollOrigin() = 0;
|
||||
|
||||
/**
|
||||
* Returns whether there's an async scroll going on.
|
||||
*
|
||||
* The argument allows a subtle distinction that's needed for APZ. When
|
||||
* `IncludeApzAnimation::No` is given, ongoing APZ animations that have
|
||||
* already been synced to the main thread are not included, which is needed so
|
||||
* that APZ can keep syncing the scroll offset properly.
|
||||
*/
|
||||
enum class IncludeApzAnimation : bool { No, Yes };
|
||||
virtual bool IsScrollAnimating(
|
||||
IncludeApzAnimation = IncludeApzAnimation::Yes) = 0;
|
||||
|
||||
/**
|
||||
* Returns the current generation counter for the scroll. This counter
|
||||
* increments every time the scroll position is set.
|
||||
|
@ -449,9 +457,12 @@ class nsIScrollableFrame : public nsIScrollbarMediator {
|
|||
/**
|
||||
* Clears the "origin of last scroll" property stored in this frame, if
|
||||
* the generation counter passed in matches the current scroll generation
|
||||
* counter.
|
||||
* counter, and clears the "origin of last smooth scroll" property if the
|
||||
* generation counter matches. It also resets whether there's an ongoing apz
|
||||
* animation.
|
||||
*/
|
||||
virtual void ResetScrollInfoIfGeneration(uint32_t aGeneration) = 0;
|
||||
virtual void ResetScrollInfoIfNeeded(uint32_t aGeneration,
|
||||
bool aApzAnimationInProgress) = 0;
|
||||
/**
|
||||
* Relative scrolling offset to be requested of apz.
|
||||
*/
|
||||
|
|
Загрузка…
Ссылка в новой задаче