Bug 738690: Properly convert patterns to userspace in the Azure-Thebes wrapper. r=jrmuizel

This commit is contained in:
Bas Schouten 2012-03-29 20:53:43 +02:00
parent c367e0d9b4
commit eaa02a2931
4 changed files with 78 additions and 4 deletions

View File

@ -73,10 +73,19 @@ public:
gfxContext::AzureState &state = mContext->CurrentState();
if (state.pattern) {
return *state.pattern->GetPattern(mContext->mDT);
return *state.pattern->GetPattern(mContext->mDT, state.patternTransformChanged ? &state.patternTransform : nsnull);
} else if (state.sourceSurface) {
Matrix transform = state.surfTransform;
if (state.patternTransformChanged) {
Matrix mat = state.patternTransform;
mat.Invert();
transform = mat * mContext->mDT->GetTransform() * transform;
}
mPattern = new (mSurfacePattern.addr())
SurfacePattern(state.sourceSurface, EXTEND_CLAMP, state.surfTransform);
SurfacePattern(state.sourceSurface, EXTEND_CLAMP, transform);
return *mPattern;
} else {
mPattern = new (mColorPattern.addr())
@ -575,6 +584,7 @@ gfxContext::Translate(const gfxPoint& pt)
MOZ_ASSERT(!mPathBuilder);
Matrix newMatrix = mDT->GetTransform();
TransformWillChange();
mDT->SetTransform(newMatrix.Translate(Float(pt.x), Float(pt.y)));
}
}
@ -588,6 +598,7 @@ gfxContext::Scale(gfxFloat x, gfxFloat y)
MOZ_ASSERT(!mPathBuilder);
Matrix newMatrix = mDT->GetTransform();
TransformWillChange();
mDT->SetTransform(newMatrix.Scale(Float(x), Float(y)));
}
}
@ -600,6 +611,7 @@ gfxContext::Rotate(gfxFloat angle)
} else {
MOZ_ASSERT(!mPathBuilder);
TransformWillChange();
Matrix rotation = Matrix::Rotation(Float(angle));
mDT->SetTransform(rotation * mDT->GetTransform());
}
@ -614,6 +626,7 @@ gfxContext::Multiply(const gfxMatrix& matrix)
} else {
MOZ_ASSERT(!mPathBuilder);
TransformWillChange();
mDT->SetTransform(ToMatrix(matrix) * mDT->GetTransform());
}
}
@ -627,6 +640,7 @@ gfxContext::SetMatrix(const gfxMatrix& matrix)
} else {
MOZ_ASSERT(!mPathBuilder);
TransformWillChange();
mDT->SetTransform(ToMatrix(matrix));
}
}
@ -639,6 +653,7 @@ gfxContext::IdentityMatrix()
} else {
MOZ_ASSERT(!mPathBuilder);
TransformWillChange();
mDT->SetTransform(Matrix());
}
}
@ -1369,6 +1384,7 @@ gfxContext::SetSource(gfxASurface *surface, const gfxPoint& offset)
} else {
CurrentState().surfTransform = Matrix(1.0f, 0, 0, 1.0f, Float(offset.x), Float(offset.y));
CurrentState().pattern = NULL;
CurrentState().patternTransformChanged = false;
CurrentState().sourceSurface =
gfxPlatform::GetPlatform()->GetSourceSurfaceForSurface(mDT, surface);
}
@ -1381,6 +1397,7 @@ gfxContext::SetPattern(gfxPattern *pattern)
cairo_set_source(mCairo, pattern->CairoPattern());
} else {
CurrentState().sourceSurface = NULL;
CurrentState().patternTransformChanged = false;
CurrentState().pattern = pattern;
}
}
@ -1582,6 +1599,7 @@ gfxContext::PopGroupToSource()
Restore();
CurrentState().sourceSurface = src;
CurrentState().pattern = NULL;
CurrentState().patternTransformChanged = false;
Matrix mat = mDT->GetTransform();
mat.Invert();
@ -2055,3 +2073,21 @@ gfxContext::GetOp()
}
}
}
/* SVG font code can change the transform after having set the pattern on the
* context. When the pattern is set it is in user space, if the transform is
* changed after doing so the pattern needs to be converted back into userspace.
* We just store the old pattern here so that we only do the work needed here
* if the pattern is actually used.
*/
void
gfxContext::TransformWillChange()
{
AzureState &state = CurrentState();
if ((state.pattern || state.sourceSurface)
&& !state.patternTransformChanged) {
state.patternTransform = mDT->GetTransform();
state.patternTransformChanged = true;
}
}

View File

@ -737,6 +737,7 @@ private:
, clipWasReset(false)
, fillRule(mozilla::gfx::FILL_WINDING)
, aaMode(mozilla::gfx::AA_SUBPIXEL)
, patternTransformChanged(false)
{}
mozilla::gfx::CompositionOp op;
@ -759,6 +760,8 @@ private:
mozilla::RefPtr<DrawTarget> drawTarget;
mozilla::RefPtr<DrawTarget> parentTarget;
mozilla::gfx::AntialiasMode aaMode;
bool patternTransformChanged;
Matrix patternTransform;
};
// This ensures mPath contains a valid path (in user space!)
@ -768,6 +771,7 @@ private:
void FillAzure(mozilla::gfx::Float aOpacity);
void PushClipsToDT(mozilla::gfx::DrawTarget *aDT);
CompositionOp GetOp();
void TransformWillChange();
bool mPathIsRect;
bool mTransformChanged;

View File

@ -148,7 +148,7 @@ gfxPattern::GetMatrix() const
}
Pattern*
gfxPattern::GetPattern(mozilla::gfx::DrawTarget *aTarget)
gfxPattern::GetPattern(DrawTarget *aTarget, Matrix *aPatternTransform)
{
if (!mPattern) {
mGfxPattern = new (mSurfacePattern.addr())
@ -185,6 +185,9 @@ gfxPattern::GetPattern(mozilla::gfx::DrawTarget *aTarget)
if (mSourceSurface) {
Matrix newMat = ToMatrix(matrix);
AdjustTransformForPattern(newMat, aTarget->GetTransform(), aPatternTransform);
newMat.Invert();
double x, y;
cairo_surface_get_device_offset(surf, &x, &y);
@ -224,6 +227,9 @@ gfxPattern::GetPattern(mozilla::gfx::DrawTarget *aTarget)
gfxMatrix matrix(*reinterpret_cast<gfxMatrix*>(&mat));
Matrix newMat = ToMatrix(matrix);
AdjustTransformForPattern(newMat, aTarget->GetTransform(), aPatternTransform);
newMat.Invert();
mGfxPattern = new (mLinearGradientPattern.addr())
@ -260,6 +266,9 @@ gfxPattern::GetPattern(mozilla::gfx::DrawTarget *aTarget)
gfxMatrix matrix(*reinterpret_cast<gfxMatrix*>(&mat));
Matrix newMat = ToMatrix(matrix);
AdjustTransformForPattern(newMat, aTarget->GetTransform(), aPatternTransform);
newMat.Invert();
double x1, y1, x2, y2, r1, r2;
@ -423,3 +432,18 @@ gfxPattern::CairoStatus()
return CAIRO_STATUS_SUCCESS;
}
}
void
gfxPattern::AdjustTransformForPattern(Matrix &aPatternTransform,
const Matrix &aCurrentTransform,
const Matrix *aOriginalTransform)
{
if (!aOriginalTransform) {
return;
}
Matrix mat = *aOriginalTransform;
mat.Invert();
aPatternTransform = mat * aCurrentTransform * aPatternTransform;
}

View File

@ -73,7 +73,13 @@ public:
void SetMatrix(const gfxMatrix& matrix);
gfxMatrix GetMatrix() const;
mozilla::gfx::Pattern *GetPattern(mozilla::gfx::DrawTarget *aTarget);
/* Get an Azure Pattern for the current Cairo pattern. aPattern transform
* specifies the transform that was set on the DrawTarget when the pattern
* was set. When this is NULL it is assumed the transform is identical
* to the current transform.
*/
mozilla::gfx::Pattern *GetPattern(mozilla::gfx::DrawTarget *aTarget,
mozilla::gfx::Matrix *aPatternTransform = nsnull);
bool IsOpaque();
enum GraphicsExtend {
@ -128,6 +134,10 @@ public:
protected:
cairo_pattern_t *mPattern;
void AdjustTransformForPattern(mozilla::gfx::Matrix &aPatternTransform,
const mozilla::gfx::Matrix &aCurrentTransform,
const mozilla::gfx::Matrix *aOriginalTransform);
union {
mozilla::AlignedStorage2<mozilla::gfx::ColorPattern> mColorPattern;
mozilla::AlignedStorage2<mozilla::gfx::LinearGradientPattern> mLinearGradientPattern;