Bug 757329: Support changing transforms while emitting path instructions. r=roc

This commit is contained in:
Bas Schouten 2012-05-22 07:29:19 +02:00
parent f3ad70ed18
commit 94bed9e6d8
3 changed files with 42 additions and 27 deletions

View File

@ -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)) {

View File

@ -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<const cairo_matrix_t&>(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<const cairo_matrix_t&>(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> 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);
}

View File

@ -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;