From 7291650c626eaefbdf41467e32f14335baa67a42 Mon Sep 17 00:00:00 2001 From: Chris Lord Date: Mon, 22 Jul 2013 09:50:05 +0100 Subject: [PATCH] Bug 876542 - Restore async fixed layer margin animation. r=roc, kats Restore the reconciliation between content document fixed position margins at render time and the fixed layer margins as retrieved via SyncViewportInfo during async panning/zooming. --- .../composite/AsyncCompositionManager.cpp | 146 +++++++++++++----- .../composite/AsyncCompositionManager.h | 6 +- 2 files changed, 111 insertions(+), 41 deletions(-) diff --git a/gfx/layers/composite/AsyncCompositionManager.cpp b/gfx/layers/composite/AsyncCompositionManager.cpp index 215748064e72..6d42ee166188 100644 --- a/gfx/layers/composite/AsyncCompositionManager.cpp +++ b/gfx/layers/composite/AsyncCompositionManager.cpp @@ -117,10 +117,96 @@ GetBaseTransform2D(Layer* aLayer, gfxMatrix* aTransform) aLayer->GetLocalTransform() : aLayer->GetTransform()).Is2D(aTransform); } +static void +TranslateShadowLayer2D(Layer* aLayer, + const gfxPoint& aTranslation) +{ + gfxMatrix layerTransform; + if (!GetBaseTransform2D(aLayer, &layerTransform)) { + return; + } + + // Apply the 2D translation to the layer transform. + layerTransform.x0 += aTranslation.x; + layerTransform.y0 += aTranslation.y; + + // The transform already takes the resolution scale into account. Since we + // will apply the resolution scale again when computing the effective + // transform, we must apply the inverse resolution scale here. + gfx3DMatrix layerTransform3D = gfx3DMatrix::From2D(layerTransform); + if (ContainerLayer* c = aLayer->AsContainerLayer()) { + layerTransform3D.Scale(1.0f/c->GetPreXScale(), + 1.0f/c->GetPreYScale(), + 1); + } + layerTransform3D.ScalePost(1.0f/aLayer->GetPostXScale(), + 1.0f/aLayer->GetPostYScale(), + 1); + + LayerComposite* layerComposite = aLayer->AsLayerComposite(); + layerComposite->SetShadowTransform(layerTransform3D); + layerComposite->SetShadowTransformSetByAnimation(false); + + const nsIntRect* clipRect = aLayer->GetClipRect(); + if (clipRect) { + nsIntRect transformedClipRect(*clipRect); + transformedClipRect.MoveBy(aTranslation.x, aTranslation.y); + layerComposite->SetShadowClipRect(&transformedClipRect); + } +} + +static bool +AccumulateLayerTransforms2D(Layer* aLayer, + Layer* aAncestor, + gfxMatrix& aMatrix) +{ + // Accumulate the transforms between this layer and the subtree root layer. + for (Layer* l = aLayer; l && l != aAncestor; l = l->GetParent()) { + gfxMatrix l2D; + if (!GetBaseTransform2D(l, &l2D)) { + return false; + } + aMatrix.Multiply(l2D); + } + + return true; +} + +static gfxPoint +GetLayerFixedMarginsOffset(Layer* aLayer, + const gfx::Margin& aFixedLayerMargins) +{ + // Work out the necessary translation, in root scrollable layer space. + // Because fixed layer margins are stored relative to the root scrollable + // layer, we can just take the difference between these values. + gfxPoint translation; + const gfxPoint& anchor = aLayer->GetFixedPositionAnchor(); + const gfx::Margin& fixedMargins = aLayer->GetFixedPositionMargins(); + + if (fixedMargins.left >= 0) { + if (anchor.x > 0) { + translation.x -= aFixedLayerMargins.right - fixedMargins.right; + } else { + translation.x += aFixedLayerMargins.left - fixedMargins.left; + } + } + + if (fixedMargins.top >= 0) { + if (anchor.y > 0) { + translation.y -= aFixedLayerMargins.bottom - fixedMargins.bottom; + } else { + translation.y += aFixedLayerMargins.top - fixedMargins.top; + } + } + + return translation; +} + void AsyncCompositionManager::AlignFixedLayersForAnchorPoint(Layer* aLayer, Layer* aTransformedSubtreeRoot, - const gfx3DMatrix& aPreviousTransformForRoot) + const gfx3DMatrix& aPreviousTransformForRoot, + const gfx::Margin& aFixedLayerMargins) { if (aLayer != aTransformedSubtreeRoot && aLayer->GetIsFixedPosition() && !aLayer->GetParent()->GetIsFixedPosition()) { @@ -130,13 +216,9 @@ AsyncCompositionManager::AlignFixedLayersForAnchorPoint(Layer* aLayer, // Accumulate the transforms between this layer and the subtree root layer. gfxMatrix ancestorTransform; - for (Layer* l = aLayer->GetParent(); l != aTransformedSubtreeRoot; - l = l->GetParent()) { - gfxMatrix l2D; - if (!GetBaseTransform2D(l, &l2D)) { - return; - } - ancestorTransform.Multiply(l2D); + if (!AccumulateLayerTransforms2D(aLayer->GetParent(), aTransformedSubtreeRoot, + ancestorTransform)) { + return; } gfxMatrix oldRootTransform; @@ -156,6 +238,11 @@ AsyncCompositionManager::AlignFixedLayersForAnchorPoint(Layer* aLayer, gfxMatrix newCumulativeTransformInverse = newCumulativeTransform; newCumulativeTransformInverse.Invert(); + // Calculate any offset necessary, in previous transform sub-tree root + // space. This is used to make sure fixed position content respects + // content document fixed position margins. + gfxPoint offsetInOldSpace = GetLayerFixedMarginsOffset(aLayer, aFixedLayerMargins); + // Now work out the translation necessary to make sure the layer doesn't // move given the new sub-tree root transform. // Transforming the locallyTransformedAnchor by oldCumulativeTransform @@ -169,40 +256,18 @@ AsyncCompositionManager::AlignFixedLayersForAnchorPoint(Layer* aLayer, if (!GetBaseTransform2D(aLayer, &layerTransform)) { return; } - gfxPoint locallyTransformedAnchor = - layerTransform.Transform(aLayer->GetFixedPositionAnchor()); + + const gfxPoint& anchor = aLayer->GetFixedPositionAnchor(); + gfxPoint locallyTransformedAnchor = layerTransform.Transform(anchor); + gfxPoint locallyTransformedOffsetAnchor = layerTransform.Transform(anchor + offsetInOldSpace); + gfxPoint oldAnchorPositionInNewSpace = newCumulativeTransformInverse.Transform( - oldCumulativeTransform.Transform(locallyTransformedAnchor)); + oldCumulativeTransform.Transform(locallyTransformedOffsetAnchor)); gfxPoint translation = oldAnchorPositionInNewSpace - locallyTransformedAnchor; // Finally, apply the 2D translation to the layer transform. - layerTransform.x0 += translation.x; - layerTransform.y0 += translation.y; - - // The transform already takes the resolution scale into account. Since we - // will apply the resolution scale again when computing the effective - // transform, we must apply the inverse resolution scale here. - gfx3DMatrix layerTransform3D = gfx3DMatrix::From2D(layerTransform); - if (ContainerLayer* c = aLayer->AsContainerLayer()) { - layerTransform3D.Scale(1.0f/c->GetPreXScale(), - 1.0f/c->GetPreYScale(), - 1); - } - layerTransform3D.ScalePost(1.0f/aLayer->GetPostXScale(), - 1.0f/aLayer->GetPostYScale(), - 1); - - LayerComposite* layerComposite = aLayer->AsLayerComposite(); - layerComposite->SetShadowTransform(layerTransform3D); - layerComposite->SetShadowTransformSetByAnimation(false); - - const nsIntRect* clipRect = aLayer->GetClipRect(); - if (clipRect) { - nsIntRect transformedClipRect(*clipRect); - transformedClipRect.MoveBy(translation.x, translation.y); - layerComposite->SetShadowClipRect(&transformedClipRect); - } + TranslateShadowLayer2D(aLayer, translation); // The transform has now been applied, so there's no need to iterate over // child layers. @@ -211,7 +276,8 @@ AsyncCompositionManager::AlignFixedLayersForAnchorPoint(Layer* aLayer, for (Layer* child = aLayer->GetFirstChild(); child; child = child->GetNextSibling()) { - AlignFixedLayersForAnchorPoint(child, aTransformedSubtreeRoot, aPreviousTransformForRoot); + AlignFixedLayersForAnchorPoint(child, aTransformedSubtreeRoot, + aPreviousTransformForRoot, aFixedLayerMargins); } } @@ -416,7 +482,7 @@ AsyncCompositionManager::ApplyAsyncContentTransformToTree(TimeStamp aCurrentFram #endif oldTransform.Scale(resolution.scale, resolution.scale, 1); - AlignFixedLayersForAnchorPoint(aLayer, aLayer, oldTransform); + AlignFixedLayersForAnchorPoint(aLayer, aLayer, oldTransform, fixedLayerMargins); appliedTransform = true; } @@ -517,7 +583,7 @@ AsyncCompositionManager::TransformScrollableLayer(Layer* aLayer, const LayoutDev // Make sure fixed position layers don't move away from their anchor points // when we're asynchronously panning or zooming - AlignFixedLayersForAnchorPoint(aLayer, aLayer, oldTransform); + AlignFixedLayersForAnchorPoint(aLayer, aLayer, oldTransform, fixedLayerMargins); } bool diff --git a/gfx/layers/composite/AsyncCompositionManager.h b/gfx/layers/composite/AsyncCompositionManager.h index 394c8deba8d9..ca557c2c6274 100644 --- a/gfx/layers/composite/AsyncCompositionManager.h +++ b/gfx/layers/composite/AsyncCompositionManager.h @@ -149,10 +149,14 @@ private: * chosen so that the layer's anchor point relative to aTransformedSubtreeRoot's * parent layer is the same as it was when aTransformedSubtreeRoot's * GetLocalTransform() was aPreviousTransformForRoot. + * This function will also adjust layers so that the given content document + * fixed position margins will be respected during asynchronous panning and + * zooming. */ void AlignFixedLayersForAnchorPoint(Layer* aLayer, Layer* aTransformedSubtreeRoot, - const gfx3DMatrix& aPreviousTransformForRoot); + const gfx3DMatrix& aPreviousTransformForRoot, + const gfx::Margin& aFixedLayerMargins); /** * DRAWING PHASE ONLY