diff --git a/gfx/2d/Matrix.h b/gfx/2d/Matrix.h index fec0ad4c6ba..62ff5b3f3dc 100644 --- a/gfx/2d/Matrix.h +++ b/gfx/2d/Matrix.h @@ -140,7 +140,7 @@ public: /* Returns true if the matrix is a rectilinear transformation (i.e. * grid-aligned rectangles are transformed to grid-aligned rectangles) */ - bool IsRectilinear() { + bool IsRectilinear() const { if (FuzzyEqual(_12, 0) && FuzzyEqual(_21, 0)) { return true; } else if (FuzzyEqual(_22, 0) && FuzzyEqual(_11, 0)) { diff --git a/gfx/thebes/gfxContext.cpp b/gfx/thebes/gfxContext.cpp index 61a06ec7b8e..78cf26d11c9 100644 --- a/gfx/thebes/gfxContext.cpp +++ b/gfx/thebes/gfxContext.cpp @@ -210,6 +210,9 @@ gfxContext::Restore() mStateStack.RemoveElementAt(mStateStack.Length() - 1); if (mPathBuilder || mPath || mPathIsRect) { + // Support here isn't fully correct if the path is continued -after- + // the restore. We don't currently have users that do this and we should + // make sure there will not be any. Sadly we can't assert this easily. mTransformChanged = true; mPathTransform = mDT->GetTransform(); } @@ -551,11 +554,9 @@ gfxContext::Translate(const gfxPoint& pt) if (mCairo) { cairo_translate(mCairo, pt.x, pt.y); } else { - MOZ_ASSERT(!mPathBuilder); - Matrix newMatrix = mDT->GetTransform(); - TransformWillChange(); - mDT->SetTransform(newMatrix.Translate(Float(pt.x), Float(pt.y))); + + ChangeTransform(newMatrix.Translate(Float(pt.x), Float(pt.y))); } } @@ -565,11 +566,9 @@ gfxContext::Scale(gfxFloat x, gfxFloat y) if (mCairo) { cairo_scale(mCairo, x, y); } else { - MOZ_ASSERT(!mPathBuilder); - Matrix newMatrix = mDT->GetTransform(); - TransformWillChange(); - mDT->SetTransform(newMatrix.Scale(Float(x), Float(y))); + + ChangeTransform(newMatrix.Scale(Float(x), Float(y))); } } @@ -579,11 +578,8 @@ gfxContext::Rotate(gfxFloat angle) if (mCairo) { cairo_rotate(mCairo, angle); } else { - MOZ_ASSERT(!mPathBuilder); - - TransformWillChange(); Matrix rotation = Matrix::Rotation(Float(angle)); - mDT->SetTransform(rotation * mDT->GetTransform()); + ChangeTransform(rotation * mDT->GetTransform()); } } @@ -594,10 +590,7 @@ gfxContext::Multiply(const gfxMatrix& matrix) const cairo_matrix_t& mat = reinterpret_cast(matrix); cairo_transform(mCairo, &mat); } else { - MOZ_ASSERT(!mPathBuilder); - - TransformWillChange(); - mDT->SetTransform(ToMatrix(matrix) * mDT->GetTransform()); + ChangeTransform(ToMatrix(matrix) * mDT->GetTransform()); } } @@ -608,10 +601,7 @@ gfxContext::SetMatrix(const gfxMatrix& matrix) const cairo_matrix_t& mat = reinterpret_cast(matrix); cairo_set_matrix(mCairo, &mat); } else { - MOZ_ASSERT(!mPathBuilder); - - TransformWillChange(); - mDT->SetTransform(ToMatrix(matrix)); + ChangeTransform(ToMatrix(matrix)); } } @@ -621,10 +611,7 @@ gfxContext::IdentityMatrix() if (mCairo) { cairo_identity_matrix(mCairo); } else { - MOZ_ASSERT(!mPathBuilder); - - TransformWillChange(); - mDT->SetTransform(Matrix()); + ChangeTransform(Matrix()); } } @@ -2075,7 +2062,7 @@ gfxContext::GetOp() * if the pattern is actually used. */ void -gfxContext::TransformWillChange() +gfxContext::ChangeTransform(Matrix &aNewMatrix) { AzureState &state = CurrentState(); @@ -2084,4 +2071,32 @@ gfxContext::TransformWillChange() state.patternTransform = mDT->GetTransform(); state.patternTransformChanged = true; } + + if (mPathBuilder || mPathIsRect) { + Matrix invMatrix = aNewMatrix; + + invMatrix.Invert(); + + Matrix toNewUS = mDT->GetTransform() * invMatrix; + + if (toNewUS.IsRectilinear() && mPathIsRect) { + mRect = toNewUS.TransformBounds(mRect); + } else if (mPathIsRect) { + mPathBuilder = mDT->CreatePathBuilder(CurrentState().fillRule); + + mPathBuilder->MoveTo(toNewUS * mRect.TopLeft()); + mPathBuilder->LineTo(toNewUS * mRect.TopRight()); + mPathBuilder->LineTo(toNewUS * mRect.BottomRight()); + mPathBuilder->LineTo(toNewUS * mRect.BottomLeft()); + mPathBuilder->Close(); + } else { + RefPtr path = mPathBuilder->Finish(); + // Create path in device space. + mPathBuilder = path->TransformedCopyToBuilder(toNewUS); + } + // No need to consider the transform changed now! + mTransformChanged = false; + } + + mDT->SetTransform(aNewMatrix); } \ No newline at end of file diff --git a/gfx/thebes/gfxContext.h b/gfx/thebes/gfxContext.h index daddbe02be2..9710df1cc4a 100644 --- a/gfx/thebes/gfxContext.h +++ b/gfx/thebes/gfxContext.h @@ -741,7 +741,7 @@ private: void FillAzure(mozilla::gfx::Float aOpacity); void PushClipsToDT(mozilla::gfx::DrawTarget *aDT); CompositionOp GetOp(); - void TransformWillChange(); + void ChangeTransform(mozilla::gfx::Matrix &aNewMatrix); bool mPathIsRect; bool mTransformChanged;