gfx3DMatrix Layer::SnapTransformTranslation(const gfx3DMatrix& aTransform, gfxMatrix* aResidualTransform) { if (aResidualTransform) { *aResidualTransform = gfxMatrix(); } gfxMatrix matrix2D; gfx3DMatrix result; if (!(mContentFlags & CONTENT_DISABLE_TRANSFORM_SNAPPING) && mManager->IsSnappingEffectiveTransforms() && aTransform.Is2D(&matrix2D) && !matrix2D.HasNonTranslation() && matrix2D.HasNonIntegerTranslation()) { gfxPoint snappedTranslation(matrix2D.GetTranslation()); snappedTranslation.Round(); gfxMatrix snappedMatrix = gfxMatrix().Translate(snappedTranslation); result = gfx3DMatrix::From2D(snappedMatrix); if (aResidualTransform) { // set aResidualTransform so that aResidual * snappedMatrix == matrix2D. // (I.e., appying snappedMatrix after aResidualTransform gives the // ideal transform.) *aResidualTransform = gfxMatrix().Translate(matrix2D.GetTranslation() - snappedTranslation); } } else { result = aTransform; } return result; }
gfx3DMatrix gfx3DMatrix::operator*(const gfx3DMatrix &aMatrix) const { if (Is2D() && aMatrix.Is2D()) { return Multiply2D(aMatrix); } gfx3DMatrix matrix; matrix._11 = _11 * aMatrix._11 + _12 * aMatrix._21 + _13 * aMatrix._31 + _14 * aMatrix._41; matrix._21 = _21 * aMatrix._11 + _22 * aMatrix._21 + _23 * aMatrix._31 + _24 * aMatrix._41; matrix._31 = _31 * aMatrix._11 + _32 * aMatrix._21 + _33 * aMatrix._31 + _34 * aMatrix._41; matrix._41 = _41 * aMatrix._11 + _42 * aMatrix._21 + _43 * aMatrix._31 + _44 * aMatrix._41; matrix._12 = _11 * aMatrix._12 + _12 * aMatrix._22 + _13 * aMatrix._32 + _14 * aMatrix._42; matrix._22 = _21 * aMatrix._12 + _22 * aMatrix._22 + _23 * aMatrix._32 + _24 * aMatrix._42; matrix._32 = _31 * aMatrix._12 + _32 * aMatrix._22 + _33 * aMatrix._32 + _34 * aMatrix._42; matrix._42 = _41 * aMatrix._12 + _42 * aMatrix._22 + _43 * aMatrix._32 + _44 * aMatrix._42; matrix._13 = _11 * aMatrix._13 + _12 * aMatrix._23 + _13 * aMatrix._33 + _14 * aMatrix._43; matrix._23 = _21 * aMatrix._13 + _22 * aMatrix._23 + _23 * aMatrix._33 + _24 * aMatrix._43; matrix._33 = _31 * aMatrix._13 + _32 * aMatrix._23 + _33 * aMatrix._33 + _34 * aMatrix._43; matrix._43 = _41 * aMatrix._13 + _42 * aMatrix._23 + _43 * aMatrix._33 + _44 * aMatrix._43; matrix._14 = _11 * aMatrix._14 + _12 * aMatrix._24 + _13 * aMatrix._34 + _14 * aMatrix._44; matrix._24 = _21 * aMatrix._14 + _22 * aMatrix._24 + _23 * aMatrix._34 + _24 * aMatrix._44; matrix._34 = _31 * aMatrix._14 + _32 * aMatrix._24 + _33 * aMatrix._34 + _34 * aMatrix._44; matrix._44 = _41 * aMatrix._14 + _42 * aMatrix._24 + _43 * aMatrix._34 + _44 * aMatrix._44; return matrix; }
gfx3DMatrix Layer::SnapTransform(const gfx3DMatrix& aTransform, const gfxRect& aSnapRect, gfxMatrix* aResidualTransform) { if (aResidualTransform) { *aResidualTransform = gfxMatrix(); } gfxMatrix matrix2D; gfx3DMatrix result; if (mManager->IsSnappingEffectiveTransforms() && aTransform.Is2D(&matrix2D) && matrix2D.HasNonIntegerTranslation() && !matrix2D.IsSingular() && !matrix2D.HasNonAxisAlignedTransform()) { gfxMatrix snappedMatrix; gfxPoint topLeft = matrix2D.Transform(aSnapRect.TopLeft()); topLeft.Round(); // first compute scale factors that scale aSnapRect to the snapped rect if (aSnapRect.IsEmpty()) { snappedMatrix.xx = matrix2D.xx; snappedMatrix.yy = matrix2D.yy; } else { gfxPoint bottomRight = matrix2D.Transform(aSnapRect.BottomRight()); bottomRight.Round(); snappedMatrix.xx = (bottomRight.x - topLeft.x)/aSnapRect.Width(); snappedMatrix.yy = (bottomRight.y - topLeft.y)/aSnapRect.Height(); } // compute translation factors that will move aSnapRect to the snapped rect // given those scale factors snappedMatrix.x0 = topLeft.x - aSnapRect.X()*snappedMatrix.xx; snappedMatrix.y0 = topLeft.y - aSnapRect.Y()*snappedMatrix.yy; result = gfx3DMatrix::From2D(snappedMatrix); if (aResidualTransform && !snappedMatrix.IsSingular()) { // set aResidualTransform so that aResidual * snappedMatrix == matrix2D. // (i.e., appying snappedMatrix after aResidualTransform gives the // ideal transform. gfxMatrix snappedMatrixInverse = snappedMatrix; snappedMatrixInverse.Invert(); *aResidualTransform = matrix2D * snappedMatrixInverse; } } else { result = aTransform; } return result; }
gfx3DMatrix Layer::SnapTransform(const gfx3DMatrix& aTransform, const gfxRect& aSnapRect, gfxMatrix* aResidualTransform) { if (aResidualTransform) { *aResidualTransform = gfxMatrix(); } gfxMatrix matrix2D; gfx3DMatrix result; if (!(mContentFlags & CONTENT_DISABLE_TRANSFORM_SNAPPING) && mManager->IsSnappingEffectiveTransforms() && aTransform.Is2D(&matrix2D) && gfxSize(1.0, 1.0) <= aSnapRect.Size() && matrix2D.PreservesAxisAlignedRectangles()) { gfxPoint transformedTopLeft = matrix2D.Transform(aSnapRect.TopLeft()); transformedTopLeft.Round(); gfxPoint transformedTopRight = matrix2D.Transform(aSnapRect.TopRight()); transformedTopRight.Round(); gfxPoint transformedBottomRight = matrix2D.Transform(aSnapRect.BottomRight()); transformedBottomRight.Round(); gfxMatrix snappedMatrix = gfxUtils::TransformRectToRect(aSnapRect, transformedTopLeft, transformedTopRight, transformedBottomRight); result = gfx3DMatrix::From2D(snappedMatrix); if (aResidualTransform && !snappedMatrix.IsSingular()) { // set aResidualTransform so that aResidual * snappedMatrix == matrix2D. // (i.e., appying snappedMatrix after aResidualTransform gives the // ideal transform. gfxMatrix snappedMatrixInverse = snappedMatrix; snappedMatrixInverse.Invert(); *aResidualTransform = matrix2D * snappedMatrixInverse; } } else { result = aTransform; } return result; }
void AsyncCompositionManager::AlignFixedLayersForAnchorPoint(Layer* aLayer, Layer* aTransformedSubtreeRoot, const gfx3DMatrix& aPreviousTransformForRoot, const LayerMargin& aFixedLayerMargins) { if (aLayer != aTransformedSubtreeRoot && aLayer->GetIsFixedPosition() && !aLayer->GetParent()->GetIsFixedPosition()) { // Insert a translation so that the position of the anchor point is the same // before and after the change to the transform of aTransformedSubtreeRoot. // This currently only works for fixed layers with 2D transforms. // Accumulate the transforms between this layer and the subtree root layer. gfxMatrix ancestorTransform; if (!AccumulateLayerTransforms2D(aLayer->GetParent(), aTransformedSubtreeRoot, ancestorTransform)) { return; } gfxMatrix oldRootTransform; gfxMatrix newRootTransform; if (!aPreviousTransformForRoot.Is2D(&oldRootTransform) || !aTransformedSubtreeRoot->GetLocalTransform().Is2D(&newRootTransform)) { return; } // Calculate the cumulative transforms between the subtree root with the // old transform and the current transform. gfxMatrix oldCumulativeTransform = ancestorTransform * oldRootTransform; gfxMatrix newCumulativeTransform = ancestorTransform * newRootTransform; if (newCumulativeTransform.IsSingular()) { return; } gfxMatrix newCumulativeTransformInverse = newCumulativeTransform; newCumulativeTransformInverse.Invert(); // Now work out the translation necessary to make sure the layer doesn't // move given the new sub-tree root transform. gfxMatrix layerTransform; if (!GetBaseTransform2D(aLayer, &layerTransform)) { return; } // 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. LayerPoint offsetInOldSubtreeLayerSpace = GetLayerFixedMarginsOffset(aLayer, aFixedLayerMargins); // Add the above offset to the anchor point so we can offset the layer by // and amount that's specified in old subtree layer space. const LayerPoint& anchorInOldSubtreeLayerSpace = aLayer->GetFixedPositionAnchor(); LayerPoint offsetAnchorInOldSubtreeLayerSpace = anchorInOldSubtreeLayerSpace + offsetInOldSubtreeLayerSpace; // Add the local layer transform to the two points to make the equation // below this section more convenient. gfxPoint anchor(anchorInOldSubtreeLayerSpace.x, anchorInOldSubtreeLayerSpace.y); gfxPoint offsetAnchor(offsetAnchorInOldSubtreeLayerSpace.x, offsetAnchorInOldSubtreeLayerSpace.y); gfxPoint locallyTransformedAnchor = layerTransform.Transform(anchor); gfxPoint locallyTransformedOffsetAnchor = layerTransform.Transform(offsetAnchor); // Transforming the locallyTransformedAnchor by oldCumulativeTransform // returns the layer's anchor point relative to the parent of // aTransformedSubtreeRoot, before the new transform was applied. // Then, applying newCumulativeTransformInverse maps that point relative // to the layer's parent, which is the same coordinate space as // locallyTransformedAnchor again, allowing us to subtract them and find // out the offset necessary to make sure the layer stays stationary. gfxPoint oldAnchorPositionInNewSpace = newCumulativeTransformInverse.Transform( oldCumulativeTransform.Transform(locallyTransformedOffsetAnchor)); gfxPoint translation = oldAnchorPositionInNewSpace - locallyTransformedAnchor; // Finally, apply the 2D translation to the layer transform. TranslateShadowLayer2D(aLayer, translation); // The transform has now been applied, so there's no need to iterate over // child layers. return; } for (Layer* child = aLayer->GetFirstChild(); child; child = child->GetNextSibling()) { AlignFixedLayersForAnchorPoint(child, aTransformedSubtreeRoot, aPreviousTransformForRoot, aFixedLayerMargins); } }