Bug 1959409 - Ensure canvas clips always get converted to the correct type. r=aosmond

When falling back from DrawTargetRecording to DrawTargetSkia, clips may be left that
were created as PathRecordings, which DrawTargetSkia will ignore.

This changes the code to unconditionally convert clips to the desired type for a
given DrawTarget (which may differ from its actual backend type) when restoring
clips, so that we avoid any such future scenarios.

Differential Revision: https://phabricator.services.mozilla.com/D245038
This commit is contained in:
Lee Salzman
2025-04-10 16:31:14 +00:00
parent 221f492e4a
commit c090de99f8
5 changed files with 13 additions and 8 deletions

View File

@@ -66,7 +66,7 @@ class CanvasPath final : public nsWrapperCache {
gfx::BackendType aBackendType) const;
already_AddRefed<gfx::Path> GetPath(const CanvasWindingRule& aWinding,
const gfx::DrawTarget* aTarget) const {
return GetPath(aWinding, aTarget->GetBackendType());
return GetPath(aWinding, aTarget->GetPathType());
}
explicit CanvasPath(nsISupports* aParent);

View File

@@ -1475,7 +1475,7 @@ void CanvasRenderingContext2D::RestoreClipsAndTransformToTarget() {
for (auto& style : mStyleStack) {
for (auto& clipOrTransform : style.clipsAndTransforms) {
if (clipOrTransform.IsClip()) {
if (mClipsNeedConverting) {
if (clipOrTransform.clip->GetBackendType() != mPathType) {
// We have possibly changed backends, so we need to convert the clips
// in case they are no longer compatible with mTarget.
RefPtr<PathBuilder> pathBuilder = mTarget->CreatePathBuilder();
@@ -1488,8 +1488,6 @@ void CanvasRenderingContext2D::RestoreClipsAndTransformToTarget() {
}
}
}
mClipsNeedConverting = false;
}
bool CanvasRenderingContext2D::BorrowTarget(const IntRect& aPersistedRect,
@@ -1684,7 +1682,7 @@ bool CanvasRenderingContext2D::EnsureTarget(ErrorResult& aError,
// Ensure any Path state is compatible with the type of DrawTarget used. This
// may require making a copy with the correct type if they (rarely) mismatch.
mPathType = newTarget->GetBackendType();
mPathType = newTarget->GetPathType();
MOZ_ASSERT(mPathType != BackendType::NONE);
if (mPathBuilder && mPathBuilder->GetBackendType() != mPathType) {
RefPtr<Path> path = mPathBuilder->Finish();
@@ -1732,7 +1730,7 @@ void CanvasRenderingContext2D::SetInitialState() {
mPathTransformDirty = false;
mPathType =
(mTarget ? mTarget : gfxPlatform::ThreadLocalScreenReferenceDrawTarget())
->GetBackendType();
->GetPathType();
MOZ_ASSERT(mPathType != BackendType::NONE);
mStyleStack.Clear();
@@ -1846,7 +1844,6 @@ bool CanvasRenderingContext2D::TrySharedTarget(
// we are already using a shared buffer provider, we are allocating a new
// one because the current one failed so let's just fall back to the basic
// provider.
mClipsNeedConverting = true;
return false;
}

View File

@@ -1225,7 +1225,6 @@ class CanvasRenderingContext2D : public nsICanvasRenderingContextInternal,
bool IsWriteOnly() const { return mWriteOnly; }
bool mWriteOnly;
bool mClipsNeedConverting = false;
uint8_t mFillTextCalls = 0;
// Flags used by the fingerprinting detection heuristic

View File

@@ -473,6 +473,7 @@ class DrawTargetWebgl : public DrawTarget, public SupportsWeakPtr {
return DrawTargetType::HARDWARE_RASTER;
}
BackendType GetBackendType() const override { return BackendType::WEBGL; }
BackendType GetPathType() const override { return BackendType::SKIA; }
IntSize GetSize() const override { return mSize; }
const RefPtr<SharedContextWebgl>& GetSharedContext() const {
return mSharedContext;

View File

@@ -1957,6 +1957,14 @@ class DrawTarget : public external::AtomicRefCounted<DrawTarget> {
return CreateSimilarDrawTarget(aSize, aFormat);
}
/**
* Get the BackendType of Paths/PathBuilders created from this DrawTarget.
* This will usually just be the same as the DrawTarget's BackendType.
* However, some DrawTargets may create PathBuilders with differing type.
*/
virtual BackendType GetPathType() const { return GetBackendType(); }
/**
* Create a path builder with the specified fillmode.
*