diff --git a/gfx/layers/FrameMetrics.h b/gfx/layers/FrameMetrics.h index e16511d82cf..f527c1ed68a 100644 --- a/gfx/layers/FrameMetrics.h +++ b/gfx/layers/FrameMetrics.h @@ -210,6 +210,12 @@ public: mZoom.scale *= aFactor; } + void CopyScrollInfoFrom(const FrameMetrics& aOther) + { + mScrollOffset = aOther.mScrollOffset; + mScrollGeneration = aOther.mScrollGeneration; + } + // --------------------------------------------------------------------------- // The following metrics are all in widget space/device pixels. // diff --git a/gfx/layers/ipc/AsyncPanZoomController.cpp b/gfx/layers/ipc/AsyncPanZoomController.cpp index 05386304799..9e07f3f1f92 100644 --- a/gfx/layers/ipc/AsyncPanZoomController.cpp +++ b/gfx/layers/ipc/AsyncPanZoomController.cpp @@ -67,7 +67,7 @@ #define APZC_LOG_FM(fm, prefix, ...) \ APZC_LOG(prefix ":" \ " i=(%ld %lld) cb=(%d %d %d %d) rcs=(%.3f %.3f) dp=(%.3f %.3f %.3f %.3f) dpm=(%.3f %.3f %.3f %.3f) um=%d " \ - "v=(%.3f %.3f %.3f %.3f) s=(%.3f %.3f) sr=(%.3f %.3f %.3f %.3f) z=(%.3f %.3f %.3f %.3f) u=(%d %llu)\n", \ + "v=(%.3f %.3f %.3f %.3f) s=(%.3f %.3f) sr=(%.3f %.3f %.3f %.3f) z=(%.3f %.3f %.3f %.3f) u=(%d %lu)\n", \ __VA_ARGS__, \ fm.mPresShellId, fm.GetScrollId(), \ fm.mCompositionBounds.x, fm.mCompositionBounds.y, fm.mCompositionBounds.width, fm.mCompositionBounds.height, \ @@ -1745,6 +1745,13 @@ void AsyncPanZoomController::NotifyLayersUpdated(const FrameMetrics& aLayerMetri mFrameMetrics.mViewport = aLayerMetrics.mViewport; } + // If the layers update was not triggered by our own repaint request, then + // we want to take the new scroll offset. Check the scroll generation as well + // to filter duplicate calls to NotifyLayersUpdated with the same scroll offset + // update message. + bool scrollOffsetUpdated = aLayerMetrics.GetScrollOffsetUpdated() + && (aLayerMetrics.GetScrollGeneration() != mFrameMetrics.GetScrollGeneration()); + if (aIsFirstPaint || isDefault) { // Initialize our internal state to something sane when the content // that was just painted is something we knew nothing about previously @@ -1781,14 +1788,12 @@ void AsyncPanZoomController::NotifyLayersUpdated(const FrameMetrics& aLayerMetri mFrameMetrics.mCumulativeResolution = aLayerMetrics.mCumulativeResolution; mFrameMetrics.mHasScrollgrab = aLayerMetrics.mHasScrollgrab; - // If the layers update was not triggered by our own repaint request, then - // we want to take the new scroll offset. - if (aLayerMetrics.GetScrollOffsetUpdated()) { + if (scrollOffsetUpdated) { APZC_LOG("%p updating scroll offset from (%f, %f) to (%f, %f)\n", this, mFrameMetrics.GetScrollOffset().x, mFrameMetrics.GetScrollOffset().y, aLayerMetrics.GetScrollOffset().x, aLayerMetrics.GetScrollOffset().y); - mFrameMetrics.SetScrollOffset(aLayerMetrics.GetScrollOffset()); + mFrameMetrics.CopyScrollInfoFrom(aLayerMetrics); // Because of the scroll offset update, any inflight paint requests are // going to be ignored by layout, and so mLastDispatchedPaintMetrics @@ -1799,13 +1804,14 @@ void AsyncPanZoomController::NotifyLayersUpdated(const FrameMetrics& aLayerMetri } } - if (aLayerMetrics.GetScrollOffsetUpdated()) { + if (scrollOffsetUpdated) { // Once layout issues a scroll offset update, it becomes impervious to // scroll offset updates from APZ until we acknowledge the update it sent. // This prevents APZ updates from clobbering scroll updates from other // more "legitimate" sources like content scripts. nsRefPtr controller = GetGeckoContentController(); if (controller) { + APZC_LOG("%p sending scroll update acknowledgement with gen %lu\n", this, aLayerMetrics.GetScrollGeneration()); controller->AcknowledgeScrollUpdate(aLayerMetrics.GetScrollId(), aLayerMetrics.GetScrollGeneration()); } diff --git a/layout/generic/nsGfxScrollFrame.cpp b/layout/generic/nsGfxScrollFrame.cpp index 12368eccdcc..f3d34758678 100644 --- a/layout/generic/nsGfxScrollFrame.cpp +++ b/layout/generic/nsGfxScrollFrame.cpp @@ -1545,6 +1545,14 @@ public: static ScrollFrameActivityTracker *gScrollFrameActivityTracker = nullptr; +// There are situations when a scroll frame is destroyed and then re-created +// for the same content element. In this case we want to increment the scroll +// generation between the old and new scrollframes. If the new one knew about +// the old one then it could steal the old generation counter and increment it +// but it doesn't have that reference so instead we use a static global to +// ensure the new one gets a fresh value. +static uint32_t sScrollGenerationCounter = 0; + ScrollFrameHelper::ScrollFrameHelper(nsContainerFrame* aOuter, bool aIsRoot) : mHScrollbarBox(nullptr) @@ -1555,7 +1563,7 @@ ScrollFrameHelper::ScrollFrameHelper(nsContainerFrame* aOuter, , mOuter(aOuter) , mAsyncScroll(nullptr) , mOriginOfLastScroll(nsGkAtoms::other) - , mScrollGeneration(0) + , mScrollGeneration(++sScrollGenerationCounter) , mDestination(0, 0) , mScrollPosAtLastPaint(0, 0) , mRestorePos(-1, -1) @@ -2071,7 +2079,7 @@ ScrollFrameHelper::ScrollToImpl(nsPoint aPt, const nsRect& aRange, nsIAtom* aOri // Update frame position for scrolling mScrolledFrame->SetPosition(mScrollPort.TopLeft() - pt); mOriginOfLastScroll = aOrigin; - mScrollGeneration++; + mScrollGeneration = ++sScrollGenerationCounter; // We pass in the amount to move visually ScrollVisual(oldScrollFramePos);