Bug 1465616 - Use layout viewport transformations to async-adjust fixed position elements. r?botond
This results in fixed position elements being attached to the layout viewport
when being async-scrolled by APZ (when the layout viewport is larger than the
visual viewport).
MozReview-Commit-ID: 2YYIDnTWgVn
--- a/gfx/layers/apz/public/APZSampler.h
+++ b/gfx/layers/apz/public/APZSampler.h
@@ -80,16 +80,17 @@ public:
const LayerMetricsWrapper& aContent,
const ScrollbarData& aThumbData,
bool aScrollbarIsDescendant,
AsyncTransformComponentMatrix* aOutClipTransform);
CSSRect GetCurrentAsyncLayoutViewport(const LayerMetricsWrapper& aLayer);
ParentLayerPoint GetCurrentAsyncScrollOffset(const LayerMetricsWrapper& aLayer);
AsyncTransform GetCurrentAsyncTransform(const LayerMetricsWrapper& aLayer);
+ AsyncTransform GetCurrentAsyncTransformForFixedAdjustment(const LayerMetricsWrapper& aLayer);
AsyncTransformComponentMatrix GetOverscrollTransform(const LayerMetricsWrapper& aLayer);
AsyncTransformComponentMatrix GetCurrentAsyncTransformWithOverscroll(const LayerMetricsWrapper& aLayer);
void MarkAsyncTransformAppliedToContent(const LayerMetricsWrapper& aLayer);
bool HasUnusedAsyncTransform(const LayerMetricsWrapper& aLayer);
/**
* Return a new AutoApplyAsyncTestAttributes instance. This should be called
--- a/gfx/layers/apz/src/APZSampler.cpp
+++ b/gfx/layers/apz/src/APZSampler.cpp
@@ -176,16 +176,26 @@ APZSampler::GetCurrentAsyncTransform(con
{
MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
AssertOnSamplerThread();
MOZ_ASSERT(aLayer.GetApzc());
return aLayer.GetApzc()->GetCurrentAsyncTransform(AsyncPanZoomController::eForCompositing);
}
+AsyncTransform
+APZSampler::GetCurrentAsyncTransformForFixedAdjustment(const LayerMetricsWrapper& aLayer)
+{
+ MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
+ AssertOnSamplerThread();
+
+ MOZ_ASSERT(aLayer.GetApzc());
+ return aLayer.GetApzc()->GetCurrentAsyncTransformForFixedAdjustment(AsyncPanZoomController::eForCompositing);
+}
+
AsyncTransformComponentMatrix
APZSampler::GetOverscrollTransform(const LayerMetricsWrapper& aLayer)
{
MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
AssertOnSamplerThread();
MOZ_ASSERT(aLayer.GetApzc());
return aLayer.GetApzc()->GetOverscrollTransform(AsyncPanZoomController::eForCompositing);
--- a/gfx/layers/apz/src/AsyncPanZoomController.cpp
+++ b/gfx/layers/apz/src/AsyncPanZoomController.cpp
@@ -3809,16 +3809,72 @@ AsyncPanZoomController::GetCurrentAsyncS
if (aMode == eForCompositing && mScrollMetadata.IsApzForceDisabled()) {
return mLastContentPaintMetrics.GetScrollOffset();
}
return GetEffectiveScrollOffset(aMode);
}
AsyncTransform
+AsyncPanZoomController::GetCurrentAsyncViewportTransform(AsyncTransformConsumer aMode) const
+{
+ RecursiveMutexAutoLock lock(mRecursiveMutex);
+
+ if (aMode == eForCompositing && mScrollMetadata.IsApzForceDisabled()) {
+ return AsyncTransform();
+ }
+
+ CSSRect lastPaintViewport;
+ if (mLastContentPaintMetrics.IsScrollable()) {
+ lastPaintViewport = mLastContentPaintMetrics.GetViewport();
+ }
+
+ CSSRect currentViewport = GetEffectiveLayoutViewport(aMode);
+ CSSPoint currentViewportOffset = currentViewport.TopLeft();
+
+ // If checkerboarding has been disallowed, clamp the scroll position to stay
+ // within rendered content.
+ //
+ // TODO: This calculation is slightly inaccurate and this function will
+ // likely report an inconsistent transformation if apz.allow_checkerboarding
+ // is disabled. The correct calculation requires the following:
+ //
+ // * Calculating a clamped visual scroll offset, like in
+ // AsyncPanZoomController::GetCurrentAsyncTransform.
+ // * Calling FrameMetrics::RecalculateViewportOffset to compute the layout
+ // viewport offset corresponding to that visual offset and using that as
+ // the clamped layout viewport offset.
+ //
+ if (!gfxPrefs::APZAllowCheckerboarding() &&
+ !mLastContentPaintMetrics.GetDisplayPort().IsEmpty()) {
+ CSSSize viewportSize = currentViewport.Size();
+ CSSPoint maxViewportOffset = lastPaintViewport.TopLeft() +
+ CSSPoint(mLastContentPaintMetrics.GetDisplayPort().XMost() - viewportSize.width,
+ mLastContentPaintMetrics.GetDisplayPort().YMost() - viewportSize.height);
+ CSSPoint minViewportOffset = lastPaintViewport.TopLeft() +
+ mLastContentPaintMetrics.GetDisplayPort().TopLeft();
+
+ if (minViewportOffset.x < maxViewportOffset.x) {
+ currentViewportOffset.x = clamped(currentViewportOffset.x, minViewportOffset.x, maxViewportOffset.x);
+ }
+ if (minViewportOffset.y < maxViewportOffset.y) {
+ currentViewportOffset.y = clamped(currentViewportOffset.y, minViewportOffset.y, maxViewportOffset.y);
+ }
+ }
+
+ CSSToParentLayerScale2D effectiveZoom = GetEffectiveZoom(aMode);
+ ParentLayerPoint translation =
+ (currentViewportOffset - lastPaintViewport.TopLeft()) * effectiveZoom;
+ LayerToParentLayerScale compositedAsyncZoom =
+ (effectiveZoom / Metrics().LayersPixelsPerCSSPixel()).ToScaleFactor();
+
+ return AsyncTransform(compositedAsyncZoom, -translation);
+}
+
+AsyncTransform
AsyncPanZoomController::GetCurrentAsyncTransform(AsyncTransformConsumer aMode) const
{
RecursiveMutexAutoLock lock(mRecursiveMutex);
if (aMode == eForCompositing && mScrollMetadata.IsApzForceDisabled()) {
return AsyncTransform();
}
@@ -3851,16 +3907,32 @@ AsyncPanZoomController::GetCurrentAsyncT
ParentLayerPoint translation =
(currentScrollOffset - lastPaintScrollOffset) * effectiveZoom;
LayerToParentLayerScale compositedAsyncZoom =
(effectiveZoom / Metrics().LayersPixelsPerCSSPixel()).ToScaleFactor();
return AsyncTransform(compositedAsyncZoom, -translation);
}
+AsyncTransform
+AsyncPanZoomController::GetCurrentAsyncTransformForFixedAdjustment(AsyncTransformConsumer aMode) const
+{
+ RecursiveMutexAutoLock lock(mRecursiveMutex);
+
+ // Use the layout viewport to adjust fixed position elements if and only if
+ // it's larger than the visual viewport (assuming we're scrolling the RCD-RSF
+ // with apz.allow_zooming enabled).
+ return (
+ gfxPrefs::APZAllowZooming() &&
+ Metrics().IsRootContent() &&
+ Metrics().GetVisualViewport().Size() <= Metrics().GetViewport().Size()
+ ) ? GetCurrentAsyncViewportTransform(aMode)
+ : GetCurrentAsyncTransform(aMode);
+}
+
AsyncTransformComponentMatrix
AsyncPanZoomController::GetCurrentAsyncTransformWithOverscroll(AsyncTransformConsumer aMode) const
{
return AsyncTransformComponentMatrix(GetCurrentAsyncTransform(aMode))
* GetOverscrollTransform(aMode);
}
CSSRect
@@ -3889,17 +3961,18 @@ AsyncPanZoomController::GetEffectiveZoom
}
return Metrics().GetZoom();
}
bool
AsyncPanZoomController::SampleCompositedAsyncTransform()
{
RecursiveMutexAutoLock lock(mRecursiveMutex);
- if (mCompositedScrollOffset != Metrics().GetScrollOffset() ||
+ if (!mCompositedLayoutViewport.IsEqualEdges(Metrics().GetViewport()) ||
+ mCompositedScrollOffset != Metrics().GetScrollOffset() ||
mCompositedZoom != Metrics().GetZoom()) {
mCompositedLayoutViewport = Metrics().GetViewport();
mCompositedScrollOffset = Metrics().GetScrollOffset();
mCompositedZoom = Metrics().GetZoom();
return true;
}
return false;
}
--- a/gfx/layers/apz/src/AsyncPanZoomController.h
+++ b/gfx/layers/apz/src/AsyncPanZoomController.h
@@ -1043,24 +1043,39 @@ public:
/**
* Return a visual effect that reflects this apzc's
* overscrolled state, if any.
*/
AsyncTransformComponentMatrix GetOverscrollTransform(AsyncTransformConsumer aMode) const;
/**
+ * Returns the incremental transformation corresponding to the async
+ * panning/zooming of the layout viewport (unlike GetCurrentAsyncTransform,
+ * which deals with async movement of the visual viewport). That is, when
+ * this transform is multiplied with the layer's existing transform, it will
+ * make the layer appear with the desired pan/zoom amount.
+ */
+ AsyncTransform GetCurrentAsyncViewportTransform(AsyncTransformConsumer aMode) const;
+
+ /**
* Returns the incremental transformation corresponding to the async pan/zoom
* in progress. That is, when this transform is multiplied with the layer's
* existing transform, it will make the layer appear with the desired pan/zoom
* amount.
*/
AsyncTransform GetCurrentAsyncTransform(AsyncTransformConsumer aMode) const;
/**
+ * Returns the incremental transformation corresponding to the async
+ * panning/zooming of the larger of the visual or layout viewport.
+ */
+ AsyncTransform GetCurrentAsyncTransformForFixedAdjustment(AsyncTransformConsumer aMode) const;
+
+ /**
* Returns the same transform as GetCurrentAsyncTransform(), but includes
* any transform due to axis over-scroll.
*/
AsyncTransformComponentMatrix GetCurrentAsyncTransformWithOverscroll(AsyncTransformConsumer aMode) const;
private:
/**
* Samples the composited async transform, making the result of
--- a/gfx/layers/composite/AsyncCompositionManager.cpp
+++ b/gfx/layers/composite/AsyncCompositionManager.cpp
@@ -1063,21 +1063,21 @@ AsyncCompositionManager::ApplyAsyncConte
// For the purpose of aligning fixed and sticky layers, we disregard
// the overscroll transform as well as any OMTA transform when computing the
// 'aCurrentTransformForRoot' parameter. This ensures that the overscroll
// and OMTA transforms are not unapplied, and therefore that the visual
// effects apply to fixed and sticky layers. We do this by using
// GetTransform() as the base transform rather than GetLocalTransform(),
// which would include those factors.
- LayerToParentLayerMatrix4x4 transformWithoutOverscrollOrOmta =
- layer->GetTransformTyped()
- * CompleteAsyncTransform(
- AdjustForClip(asyncTransformWithoutOverscroll, layer));
-
+ AsyncTransform asyncTransformForFixedAdjustment
+ = sampler->GetCurrentAsyncTransformForFixedAdjustment(wrapper);
+ LayerToParentLayerMatrix4x4 transformWithoutOverscrollOrOmta
+ = layer->GetTransformTyped()
+ * CompleteAsyncTransform(AdjustForClip(asyncTransformForFixedAdjustment, layer));
AlignFixedAndStickyLayers(layer, layer, metrics.GetScrollId(), oldTransform,
transformWithoutOverscrollOrOmta, fixedLayerMargins,
&clipPartsCache);
// Combine the local clip with the ancestor scrollframe clip. This is not
// included in the async transform above, since the ancestor clip should not
// move with this APZC.
if (scrollMetadata.HasScrollClip()) {