Bug 1224976. Recover from singular-matrix cairo errors. r=mattwoodrow

This commit is contained in:
Robert O'Callahan 2015-11-16 17:35:23 +13:00
parent d2e0f299e2
commit 1ed2fac306
5 changed files with 82 additions and 9 deletions

View File

@ -590,6 +590,7 @@ NeedIntermediateSurface(const Pattern& aPattern, const DrawOptions& aOptions)
DrawTargetCairo::DrawTargetCairo()
: mContext(nullptr)
, mSurface(nullptr)
, mTransformSingular(false)
, mLockedBits(nullptr)
{
}
@ -775,6 +776,10 @@ DrawTargetCairo::DrawSurface(SourceSurface *aSurface,
const DrawSurfaceOptions &aSurfOptions,
const DrawOptions &aOptions)
{
if (mTransformSingular) {
return;
}
AutoPrepareForDrawing prep(this, mContext);
AutoClearDeviceOffset clear(aSurface);
@ -968,6 +973,10 @@ DrawTargetCairo::FillRect(const Rect &aRect,
const Pattern &aPattern,
const DrawOptions &aOptions)
{
if (mTransformSingular) {
return;
}
AutoPrepareForDrawing prep(this, mContext);
bool restoreTransform = false;
@ -1043,6 +1052,10 @@ DrawTargetCairo::CopySurface(SourceSurface *aSurface,
const IntRect &aSource,
const IntPoint &aDest)
{
if (mTransformSingular) {
return;
}
AutoPrepareForDrawing prep(this, mContext);
AutoClearDeviceOffset clear(aSurface);
@ -1065,6 +1078,10 @@ void
DrawTargetCairo::CopyRect(const IntRect &aSource,
const IntPoint &aDest)
{
if (mTransformSingular) {
return;
}
AutoPrepareForDrawing prep(this, mContext);
IntRect source = aSource;
@ -1097,6 +1114,10 @@ DrawTargetCairo::CopyRect(const IntRect &aSource,
void
DrawTargetCairo::ClearRect(const Rect& aRect)
{
if (mTransformSingular) {
return;
}
AutoPrepareForDrawing prep(this, mContext);
if (!mContext || aRect.Width() <= 0 || aRect.Height() <= 0 ||
@ -1119,6 +1140,10 @@ DrawTargetCairo::StrokeRect(const Rect &aRect,
const StrokeOptions &aStrokeOptions /* = StrokeOptions() */,
const DrawOptions &aOptions /* = DrawOptions() */)
{
if (mTransformSingular) {
return;
}
AutoPrepareForDrawing prep(this, mContext);
cairo_new_path(mContext);
@ -1134,6 +1159,10 @@ DrawTargetCairo::StrokeLine(const Point &aStart,
const StrokeOptions &aStrokeOptions /* = StrokeOptions() */,
const DrawOptions &aOptions /* = DrawOptions() */)
{
if (mTransformSingular) {
return;
}
AutoPrepareForDrawing prep(this, mContext);
cairo_new_path(mContext);
@ -1149,6 +1178,10 @@ DrawTargetCairo::Stroke(const Path *aPath,
const StrokeOptions &aStrokeOptions /* = StrokeOptions() */,
const DrawOptions &aOptions /* = DrawOptions() */)
{
if (mTransformSingular) {
return;
}
AutoPrepareForDrawing prep(this, mContext, aPath);
if (aPath->GetBackendType() != BackendType::CAIRO)
@ -1165,6 +1198,10 @@ DrawTargetCairo::Fill(const Path *aPath,
const Pattern &aPattern,
const DrawOptions &aOptions /* = DrawOptions() */)
{
if (mTransformSingular) {
return;
}
AutoPrepareForDrawing prep(this, mContext, aPath);
if (aPath->GetBackendType() != BackendType::CAIRO)
@ -1193,6 +1230,10 @@ DrawTargetCairo::FillGlyphs(ScaledFont *aFont,
const DrawOptions &aOptions,
const GlyphRenderingOptions*)
{
if (mTransformSingular) {
return;
}
AutoPrepareForDrawing prep(this, mContext);
AutoClearDeviceOffset clear(aPattern);
@ -1232,6 +1273,10 @@ DrawTargetCairo::Mask(const Pattern &aSource,
const Pattern &aMask,
const DrawOptions &aOptions /* = DrawOptions() */)
{
if (mTransformSingular) {
return;
}
AutoPrepareForDrawing prep(this, mContext);
AutoClearDeviceOffset clearSource(aSource);
AutoClearDeviceOffset clearMask(aMask);
@ -1270,6 +1315,10 @@ DrawTargetCairo::MaskSurface(const Pattern &aSource,
Point aOffset,
const DrawOptions &aOptions)
{
if (mTransformSingular) {
return;
}
AutoPrepareForDrawing prep(this, mContext);
AutoClearDeviceOffset clearSource(aSource);
AutoClearDeviceOffset clearMask(aMask);
@ -1336,7 +1385,13 @@ DrawTargetCairo::PushClip(const Path *aPath)
cairo_save(mContext);
PathCairo* path = const_cast<PathCairo*>(static_cast<const PathCairo*>(aPath));
path->SetPathOnContext(mContext);
if (mTransformSingular) {
cairo_new_path(mContext);
cairo_rectangle(mContext, 0, 0, 0, 0);
} else {
path->SetPathOnContext(mContext);
}
cairo_clip_preserve(mContext);
}
@ -1347,7 +1402,11 @@ DrawTargetCairo::PushClipRect(const Rect& aRect)
cairo_save(mContext);
cairo_new_path(mContext);
cairo_rectangle(mContext, aRect.X(), aRect.Y(), aRect.Width(), aRect.Height());
if (mTransformSingular) {
cairo_rectangle(mContext, 0, 0, 0, 0);
} else {
cairo_rectangle(mContext, aRect.X(), aRect.Y(), aRect.Width(), aRect.Height());
}
cairo_clip_preserve(mContext);
}
@ -1364,9 +1423,6 @@ DrawTargetCairo::PopClip()
cairo_restore(mContext);
cairo_set_matrix(mContext, &mat);
MOZ_ASSERT(cairo_status(mContext) || GetTransform() == Matrix(mat.xx, mat.yx, mat.xy, mat.yy, mat.x0, mat.y0),
"Transforms are out of sync");
}
already_AddRefed<PathBuilder>
@ -1709,11 +1765,14 @@ DrawTargetCairo::WillChange(const Path* aPath /* = nullptr */)
void
DrawTargetCairo::SetTransform(const Matrix& aTransform)
{
mTransform = aTransform;
DrawTarget::SetTransform(aTransform);
cairo_matrix_t mat;
GfxMatrixToCairoMatrix(mTransform, mat);
cairo_set_matrix(mContext, &mat);
mTransformSingular = aTransform.IsSingular();
if (!mTransformSingular) {
cairo_matrix_t mat;
GfxMatrixToCairoMatrix(mTransform, mat);
cairo_set_matrix(mContext, &mat);
}
}
Rect

View File

@ -209,6 +209,7 @@ private: // data
cairo_t* mContext;
cairo_surface_t* mSurface;
IntSize mSize;
bool mTransformSingular;
uint8_t* mLockedBits;

View File

@ -0,0 +1,2 @@
<!DOCTYPE HTML>
<div style="background:black; width:10px; height:10px"></div>

View File

@ -0,0 +1,10 @@
<!DOCTYPE HTML>
<canvas id="c"></canvas>
<script>
var ctx = c.getContext('2d');
ctx.scale(0,1);
ctx.fillStyle = "black";
ctx.fillRect(0, 0, 10, 10);
ctx.setTransform(1, 0, 0, 1, 0, 0);
ctx.fillRect(0, 0, 10, 10);
</script>

View File

@ -107,3 +107,4 @@ fuzzy-if(azureQuartz,2,128) fuzzy-if(d2d,12,21) fuzzy-if(d2d&&/^Windows\x20NT\x2
fuzzy-if(Mulet,45,2) == 1107096-invisibles.html 1107096-invisibles-ref.html
== 1151821-1.html 1151821-1-ref.html
== 1201272-1.html 1201272-1-ref.html
== 1224976-1.html 1224976-1-ref.html