bool AsyncPanZoomController::SampleContentTransformForFrame(const TimeStamp& aSampleTime, const FrameMetrics& aFrame, const gfx3DMatrix& aCurrentTransform, gfx3DMatrix* aNewTransform) { // The eventual return value of this function. The compositor needs to know // whether or not to advance by a frame as soon as it can. For example, if a // fling is happening, it has to keep compositing so that the animation is // smooth. If an animation frame is requested, it is the compositor's // responsibility to schedule a composite. bool requestAnimationFrame = false; // Scales on the root layer, on what's currently painted. float rootScaleX = aCurrentTransform.GetXScale(), rootScaleY = aCurrentTransform.GetYScale(); nsIntPoint metricsScrollOffset(0, 0); nsIntPoint scrollOffset; float localScaleX, localScaleY; { MonitorAutoLock mon(mMonitor); // If a fling is currently happening, apply it now. We can pull the updated // metrics afterwards. requestAnimationFrame = requestAnimationFrame || DoFling(aSampleTime - mLastSampleTime); // Current local transform; this is not what's painted but rather what PZC has // transformed due to touches like panning or pinching. Eventually, the root // layer transform will become this during runtime, but we must wait for Gecko // to repaint. localScaleX = mFrameMetrics.mResolution.width; localScaleY = mFrameMetrics.mResolution.height; if (aFrame.IsScrollable()) { metricsScrollOffset = aFrame.mViewportScrollOffset; } scrollOffset = mFrameMetrics.mViewportScrollOffset; } nsIntPoint scrollCompensation( (scrollOffset.x / rootScaleX - metricsScrollOffset.x) * localScaleX, (scrollOffset.y / rootScaleY - metricsScrollOffset.y) * localScaleY); ViewTransform treeTransform(-scrollCompensation, localScaleX, localScaleY); *aNewTransform = gfx3DMatrix(treeTransform) * aCurrentTransform; mLastSampleTime = aSampleTime; return requestAnimationFrame; }
/** * Recover the z component from a 2d transformed point by finding the intersection * of a line through the point in the z direction and the transformed plane. * * We want to solve: * * point = normal . (p0 - l0) / normal . l */ static gfxFloat RecoverZDepth(const gfx3DMatrix& aTransform, const gfxPoint& aPoint) { const gfxPoint3D l(0, 0, 1); gfxPoint3D l0 = gfxPoint3D(aPoint.x, aPoint.y, 0); gfxPoint3D p0 = aTransform.Transform3D(gfxPoint3D(0, 0, 0)); gfxPoint3D normal = aTransform.GetNormalVector(); gfxFloat n = normal.DotProduct(p0 - l0); gfxFloat d = normal.DotProduct(l); if (!d) { return 0; } return n/d; }
static LayoutDeviceRect ApplyScreenToLayoutTransform(const gfx3DMatrix& aTransform, const ScreenRect& aScreenRect) { gfxRect input(aScreenRect.x, aScreenRect.y, aScreenRect.width, aScreenRect.height); gfxRect output = aTransform.TransformBounds(input); return LayoutDeviceRect(output.x, output.y, output.width, output.height); }
/* Helper function to process a matrix entry. */ static void ProcessMatrix(gfx3DMatrix& aMatrix, const nsCSSValue::Array* aData, nsStyleContext* aContext, nsPresContext* aPresContext, bool& aCanStoreInRuleTree, nsRect& aBounds) { NS_PRECONDITION(aData->Count() == 7, "Invalid array!"); gfxMatrix result; /* Take the first four elements out of the array as floats and store * them. */ result._11 = aData->Item(1).GetFloatValue(); result._12 = aData->Item(2).GetFloatValue(); result._21 = aData->Item(3).GetFloatValue(); result._22 = aData->Item(4).GetFloatValue(); /* The last two elements have their length parts stored in aDelta * and their percent parts stored in aX[0] and aY[1]. */ result._31 = ProcessTranslatePart(aData->Item(5), aContext, aPresContext, aCanStoreInRuleTree, aBounds.Width()); result._32 = ProcessTranslatePart(aData->Item(6), aContext, aPresContext, aCanStoreInRuleTree, aBounds.Height()); aMatrix.PreMultiply(result); }
static void ProcessRotateY(gfx3DMatrix& aMatrix, const nsCSSValue::Array* aData) { NS_PRECONDITION(aData->Count() == 2, "Invalid array!"); double theta = aData->Item(1).GetAngleValueInRadians(); aMatrix.RotateY(theta); }
static void ProcessTranslate3D(gfx3DMatrix& aMatrix, const nsCSSValue::Array* aData, nsStyleContext* aContext, nsPresContext* aPresContext, bool& aCanStoreInRuleTree, nsRect& aBounds) { NS_PRECONDITION(aData->Count() == 4, "Invalid array!"); Point3D temp; temp.x = ProcessTranslatePart(aData->Item(1), aContext, aPresContext, aCanStoreInRuleTree, aBounds.Width()); temp.y = ProcessTranslatePart(aData->Item(2), aContext, aPresContext, aCanStoreInRuleTree, aBounds.Height()); temp.z = ProcessTranslatePart(aData->Item(3), aContext, aPresContext, aCanStoreInRuleTree, 0); aMatrix.Translate(temp); }
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; }
void AsyncPanZoomController::GetContentTransformForFrame(const FrameMetrics& aFrame, const gfx3DMatrix& aRootTransform, const gfxSize& aWidgetSize, gfx3DMatrix* aTreeTransform, gfxPoint* aReverseViewTranslation) { // Scales on the root layer, on what's currently painted. float rootScaleX = aRootTransform.GetXScale(), rootScaleY = aRootTransform.GetYScale(); // Current local transform; this is not what's painted but rather what PZC has // transformed due to touches like panning or pinching. Eventually, the root // layer transform will become this during runtime, but we must wait for Gecko // to repaint. float localScaleX = mFrameMetrics.mResolution.width, localScaleY = mFrameMetrics.mResolution.height; // Handle transformations for asynchronous panning and zooming. We determine the // zoom used by Gecko from the transformation set on the root layer, and we // determine the scroll offset used by Gecko from the frame metrics of the // primary scrollable layer. We compare this to the desired zoom and scroll // offset in the view transform we obtained from Java in order to compute the // transformation we need to apply. float tempScaleDiffX = rootScaleX * localScaleX; float tempScaleDiffY = rootScaleY * localScaleY; nsIntPoint metricsScrollOffset(0, 0); if (aFrame.IsScrollable()) metricsScrollOffset = aFrame.mViewportScrollOffset; nsIntPoint scrollCompensation( mFrameMetrics.mViewportScrollOffset.x / rootScaleX - metricsScrollOffset.x, mFrameMetrics.mViewportScrollOffset.y / rootScaleY - metricsScrollOffset.y); ViewTransform treeTransform(-scrollCompensation, localScaleX, localScaleY); *aTreeTransform = gfx3DMatrix(treeTransform); float offsetX = mFrameMetrics.mViewportScrollOffset.x / tempScaleDiffX, offsetY = mFrameMetrics.mViewportScrollOffset.y / tempScaleDiffY; nsIntRect localContentRect = mFrameMetrics.mContentRect; offsetX = NS_MAX((float)localContentRect.x, NS_MIN(offsetX, (float)(localContentRect.XMost() - aWidgetSize.width))); offsetY = NS_MAX((float)localContentRect.y, NS_MIN(offsetY, (float)(localContentRect.YMost() - aWidgetSize.height))); *aReverseViewTranslation = gfxPoint(offsetX - metricsScrollOffset.x, offsetY - metricsScrollOffset.y); }
/* Helper function to set up a scale matrix. */ static void ProcessScaleHelper(gfx3DMatrix& aMatrix, float aXScale, float aYScale, float aZScale) { aMatrix.Scale(aXScale, aYScale, aZScale); }
static void ProcessPerspective(gfx3DMatrix& aMatrix, const nsCSSValue::Array* aData, nsStyleContext *aContext, nsPresContext *aPresContext, bool &aCanStoreInRuleTree) { NS_PRECONDITION(aData->Count() == 2, "Invalid array!"); float depth = ProcessTranslatePart(aData->Item(1), aContext, aPresContext, aCanStoreInRuleTree, 0); aMatrix.Perspective(depth); }
static void ProcessTranslateZ(gfx3DMatrix& aMatrix, const nsCSSValue::Array* aData, nsStyleContext* aContext, nsPresContext* aPresContext, bool& aCanStoreInRuleTree) { NS_PRECONDITION(aData->Count() == 2, "Invalid array!"); Point3D temp; temp.z = ProcessTranslatePart(aData->Item(1), aContext, aPresContext, aCanStoreInRuleTree, 0); aMatrix.Translate(temp); }
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; }
static nsIntRect TransformRect(const nsIntRect& aRect, const gfx3DMatrix& aTransform) { if (aRect.IsEmpty()) { return nsIntRect(); } gfxRect rect(aRect.x, aRect.y, aRect.width, aRect.height); rect = aTransform.TransformBounds(rect); rect.RoundOut(); nsIntRect intRect; if (!gfxUtils::GfxRectToIntRect(rect, &intRect)) { return nsIntRect(); } return intRect; }
static void SubtractTransformedRegion(nsIntRegion& aRegion, const nsIntRegion& aRegionToSubtract, const gfx3DMatrix& aTransform) { if (aRegionToSubtract.IsEmpty()) { return; } // For each rect in the region, find out its bounds in screen space and // subtract it from the screen region. nsIntRegionRectIterator it(aRegionToSubtract); while (const nsIntRect* rect = it.Next()) { gfxRect incompleteRect = aTransform.TransformBounds(gfxRect(*rect)); aRegion.Sub(aRegion, nsIntRect(incompleteRect.x, incompleteRect.y, incompleteRect.width, incompleteRect.height)); } }
static void Transform(DataSourceSurface* aDest, DataSourceSurface* aSource, const gfx3DMatrix& aTransform, const Point& aDestOffset) { if (aTransform.IsSingular()) { return; } IntSize destSize = aDest->GetSize(); SkImageInfo destInfo = SkImageInfo::Make(destSize.width, destSize.height, kBGRA_8888_SkColorType, kPremul_SkAlphaType); SkBitmap destBitmap; destBitmap.setInfo(destInfo, aDest->Stride()); destBitmap.setPixels((uint32_t*)aDest->GetData()); SkCanvas destCanvas(destBitmap); IntSize srcSize = aSource->GetSize(); SkImageInfo srcInfo = SkImageInfo::Make(srcSize.width, srcSize.height, kBGRA_8888_SkColorType, kPremul_SkAlphaType); SkBitmap src; src.setInfo(srcInfo, aSource->Stride()); src.setPixels((uint32_t*)aSource->GetData()); gfx3DMatrix transform = aTransform; transform.TranslatePost(Point3D(-aDestOffset.x, -aDestOffset.y, 0)); destCanvas.setMatrix(Matrix3DToSkia(transform)); SkPaint paint; paint.setXfermodeMode(SkXfermode::kSrc_Mode); paint.setAntiAlias(true); paint.setFilterLevel(SkPaint::kLow_FilterLevel); SkRect destRect = SkRect::MakeXYWH(0, 0, srcSize.width, srcSize.height); destCanvas.drawBitmapRectToRect(src, nullptr, destRect, &paint); }
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; }
static void ProcessMatrix3D(gfx3DMatrix& aMatrix, const nsCSSValue::Array* aData, nsStyleContext* aContext, nsPresContext* aPresContext, bool& aCanStoreInRuleTree, nsRect& aBounds) { NS_PRECONDITION(aData->Count() == 17, "Invalid array!"); gfx3DMatrix temp; temp._11 = aData->Item(1).GetFloatValue(); temp._12 = aData->Item(2).GetFloatValue(); temp._13 = aData->Item(3).GetFloatValue(); temp._14 = aData->Item(4).GetFloatValue(); temp._21 = aData->Item(5).GetFloatValue(); temp._22 = aData->Item(6).GetFloatValue(); temp._23 = aData->Item(7).GetFloatValue(); temp._24 = aData->Item(8).GetFloatValue(); temp._31 = aData->Item(9).GetFloatValue(); temp._32 = aData->Item(10).GetFloatValue(); temp._33 = aData->Item(11).GetFloatValue(); temp._34 = aData->Item(12).GetFloatValue(); temp._44 = aData->Item(16).GetFloatValue(); temp._41 = ProcessTranslatePart(aData->Item(13), aContext, aPresContext, aCanStoreInRuleTree, aBounds.Width()); temp._42 = ProcessTranslatePart(aData->Item(14), aContext, aPresContext, aCanStoreInRuleTree, aBounds.Height()); temp._43 = ProcessTranslatePart(aData->Item(15), aContext, aPresContext, aCanStoreInRuleTree, aBounds.Height()); aMatrix.PreMultiply(temp); }
static LayoutDeviceRect TransformCompositionBounds(const ParentLayerRect& aCompositionBounds, const CSSToParentLayerScale& aZoom, const ScreenPoint& aScrollOffset, const CSSToScreenScale& aResolution, const gfx3DMatrix& aTransformScreenToLayout) { // Transform the current composition bounds into transformed layout device // space by compensating for the difference in resolution and subtracting the // old composition bounds origin. ScreenRect offsetViewportRect = (aCompositionBounds / aZoom) * aResolution; offsetViewportRect.MoveBy(-aScrollOffset); gfxRect transformedViewport = aTransformScreenToLayout.TransformBounds( gfxRect(offsetViewportRect.x, offsetViewportRect.y, offsetViewportRect.width, offsetViewportRect.height)); return LayoutDeviceRect(transformedViewport.x, transformedViewport.y, transformedViewport.width, transformedViewport.height); }
static float GetDisplayportCoverage(const gfx::Rect& aDisplayPort, const gfx3DMatrix& aTransformToScreen, const nsIntRect& aScreenRect) { gfxRect transformedDisplayport = aTransformToScreen.TransformBounds(gfxRect(aDisplayPort.x, aDisplayPort.y, aDisplayPort.width, aDisplayPort.height)); transformedDisplayport.RoundOut(); nsIntRect displayport = nsIntRect(transformedDisplayport.x, transformedDisplayport.y, transformedDisplayport.width, transformedDisplayport.height); if (!displayport.Contains(aScreenRect)) { nsIntRegion coveredRegion; coveredRegion.And(aScreenRect, displayport); return GetRegionArea(coveredRegion) / (float)(aScreenRect.width * aScreenRect.height); } return 1.0f; }
/* Helper function to process a translate function. */ static void ProcessTranslate(gfx3DMatrix& aMatrix, const nsCSSValue::Array* aData, nsStyleContext* aContext, nsPresContext* aPresContext, bool& aCanStoreInRuleTree, nsRect& aBounds) { NS_PRECONDITION(aData->Count() == 2 || aData->Count() == 3, "Invalid array!"); Point3D temp; temp.x = ProcessTranslatePart(aData->Item(1), aContext, aPresContext, aCanStoreInRuleTree, aBounds.Width()); /* If we read in a Y component, set it appropriately */ if (aData->Count() == 3) { temp.y = ProcessTranslatePart(aData->Item(2), aContext, aPresContext, aCanStoreInRuleTree, aBounds.Height()); } aMatrix.Translate(temp); }
/* Helper function that, given a set of angles, constructs the appropriate * skew matrix. */ static void ProcessSkewHelper(gfx3DMatrix& aMatrix, double aXAngle, double aYAngle) { aMatrix.SkewXY(aXAngle, aYAngle); }
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); } }
void LayerPropertiesBase::MoveBy(const nsIntPoint& aOffset) { mTransform.TranslatePost(gfxPoint3D(aOffset.x, aOffset.y, 0)); }