diff --git a/dom/canvas/CanvasRenderingContext2D.cpp b/dom/canvas/CanvasRenderingContext2D.cpp index 6edbbceaf5da..a7b164836582 100644 --- a/dom/canvas/CanvasRenderingContext2D.cpp +++ b/dom/canvas/CanvasRenderingContext2D.cpp @@ -1505,6 +1505,33 @@ CanvasRenderingContext2D::OnStableState() mHasPendingStableStateCallback = false; } +void +CanvasRenderingContext2D::RestoreClipsAndTransformToTarget() +{ + // Restore clips and transform. + mTarget->SetTransform(Matrix()); + + if (mTarget->GetBackendType() == gfx::BackendType::CAIRO) { + // Cairo doesn't play well with huge clips. When given a very big clip it + // will try to allocate big mask surface without taking the target + // size into account which can cause OOM. See bug 1034593. + // This limits the clip extents to the size of the canvas. + // A fix in Cairo would probably be preferable, but requires somewhat + // invasive changes. + mTarget->PushClipRect(gfx::Rect(0, 0, mWidth, mHeight)); + } + + for (const auto& style : mStyleStack) { + for (const auto& clipOrTransform : style.clipsAndTransforms) { + if (clipOrTransform.IsClip()) { + mTarget->PushClip(clipOrTransform.clip); + } else { + mTarget->SetTransform(clipOrTransform.transform); + } + } + } +} + CanvasRenderingContext2D::RenderingMode CanvasRenderingContext2D::EnsureTarget(const gfx::Rect* aCoveredRect, RenderingMode aRenderingMode) @@ -1556,7 +1583,13 @@ CanvasRenderingContext2D::EnsureTarget(const gfx::Rect* aCoveredRect, : IntRect(0, 0, mWidth, mHeight); mTarget = mBufferProvider->BorrowDrawTarget(persistedRect); - mode = mRenderingMode; + if (mTarget && !mBufferProvider->PreservesDrawingState()) { + RestoreClipsAndTransformToTarget(); + } + + if (mTarget) { + return mode; + } } mIsSkiaGL = false; @@ -1649,28 +1682,7 @@ CanvasRenderingContext2D::EnsureTarget(const gfx::Rect* aCoveredRect, if (mBufferProvider != oldBufferProvider || !mBufferProvider || !mBufferProvider->PreservesDrawingState()) { - // Restore clips and transform. - mTarget->SetTransform(Matrix()); - - if (mTarget->GetBackendType() == gfx::BackendType::CAIRO) { - // Cairo doesn't play well with huge clips. When given a very big clip it - // will try to allocate big mask surface without taking the target - // size into account which can cause OOM. See bug 1034593. - // This limits the clip extents to the size of the canvas. - // A fix in Cairo would probably be preferable, but requires somewhat - // invasive changes. - mTarget->PushClipRect(canvasRect); - } - - for (const auto& style : mStyleStack) { - for (const auto& clipOrTransform : style.clipsAndTransforms) { - if (clipOrTransform.IsClip()) { - mTarget->PushClip(clipOrTransform.clip); - } else { - mTarget->SetTransform(clipOrTransform.transform); - } - } - } + RestoreClipsAndTransformToTarget(); } } else { EnsureErrorTarget(); @@ -1792,7 +1804,7 @@ CanvasRenderingContext2D::ReturnTarget(bool aForceReset) if (mTarget->GetBackendType() == gfx::BackendType::CAIRO) { // With the cairo backend we pushed an extra clip rect which we have to - // balance out here. See the comment in EnsureDrawTarget. + // balance out here. See the comment in RestoreClipsAndTransformToTarget. mTarget->PopClip(); } } diff --git a/dom/canvas/CanvasRenderingContext2D.h b/dom/canvas/CanvasRenderingContext2D.h index d76213280527..373421bd3a45 100644 --- a/dom/canvas/CanvasRenderingContext2D.h +++ b/dom/canvas/CanvasRenderingContext2D.h @@ -643,6 +643,8 @@ protected: RenderingMode EnsureTarget(const gfx::Rect* aCoveredRect = nullptr, RenderingMode aRenderMode = RenderingMode::DefaultBackendMode); + void RestoreClipsAndTransformToTarget(); + /** * This method is run at the end of the event-loop spin where * ScheduleStableStateCallback was called.