From 1ed2fac306a4e7ffac6bd0a144ebef7593460331 Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Mon, 16 Nov 2015 17:35:23 +1300 Subject: [PATCH] Bug 1224976. Recover from singular-matrix cairo errors. r=mattwoodrow --- gfx/2d/DrawTargetCairo.cpp | 77 ++++++++++++++++++++--- gfx/2d/DrawTargetCairo.h | 1 + layout/reftests/canvas/1224976-1-ref.html | 2 + layout/reftests/canvas/1224976-1.html | 10 +++ layout/reftests/canvas/reftest.list | 1 + 5 files changed, 82 insertions(+), 9 deletions(-) create mode 100644 layout/reftests/canvas/1224976-1-ref.html create mode 100644 layout/reftests/canvas/1224976-1.html diff --git a/gfx/2d/DrawTargetCairo.cpp b/gfx/2d/DrawTargetCairo.cpp index 8555c2be381..2b12034efc5 100644 --- a/gfx/2d/DrawTargetCairo.cpp +++ b/gfx/2d/DrawTargetCairo.cpp @@ -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(static_cast(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 @@ -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 diff --git a/gfx/2d/DrawTargetCairo.h b/gfx/2d/DrawTargetCairo.h index f6a5dc60054..216e1fd1905 100644 --- a/gfx/2d/DrawTargetCairo.h +++ b/gfx/2d/DrawTargetCairo.h @@ -209,6 +209,7 @@ private: // data cairo_t* mContext; cairo_surface_t* mSurface; IntSize mSize; + bool mTransformSingular; uint8_t* mLockedBits; diff --git a/layout/reftests/canvas/1224976-1-ref.html b/layout/reftests/canvas/1224976-1-ref.html new file mode 100644 index 00000000000..24b18fad304 --- /dev/null +++ b/layout/reftests/canvas/1224976-1-ref.html @@ -0,0 +1,2 @@ + +
diff --git a/layout/reftests/canvas/1224976-1.html b/layout/reftests/canvas/1224976-1.html new file mode 100644 index 00000000000..63badf019d3 --- /dev/null +++ b/layout/reftests/canvas/1224976-1.html @@ -0,0 +1,10 @@ + + + diff --git a/layout/reftests/canvas/reftest.list b/layout/reftests/canvas/reftest.list index b06b1876de4..62c3ada7149 100644 --- a/layout/reftests/canvas/reftest.list +++ b/layout/reftests/canvas/reftest.list @@ -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