From 90d2624508b4c4c353a7b95b2f02baf422805493 Mon Sep 17 00:00:00 2001 From: Markus Stange Date: Wed, 2 May 2018 11:23:53 -0400 Subject: [PATCH] Bug 1219985 - The canvas rendering context 2d should be opaque if either the moz-opaque attribute is set or if it has been initialized with alpha:false. r=jrmuizel If the canvas is cleared by setting the width or height attributes, its opaqueness should not be affected. This patch keeps support for moz-opaque, and also keeps the behavior that changing the moz-opaque attribute clears the canvas, even if this does not affect the actual opaqueness of the canvas. MozReview-Commit-ID: LOlsJxiP9kc --HG-- extra : rebase_source : 8bb95b1d5932c39a8085e007f9fd1b88b97afe55 --- dom/canvas/CanvasRenderingContext2D.cpp | 25 +++++++++++++------ dom/canvas/CanvasRenderingContext2D.h | 16 +++++++++++- dom/canvas/CanvasRenderingContextHelper.cpp | 2 +- dom/canvas/ImageBitmapRenderingContext.cpp | 3 ++- dom/canvas/ImageBitmapRenderingContext.h | 2 +- dom/canvas/WebGLContext.h | 2 +- .../nsICanvasRenderingContextInternal.h | 13 +++++++--- layout/reftests/bugs/1219985-1.html | 16 ++++++++++++ layout/reftests/bugs/1219985-2.html | 17 +++++++++++++ layout/reftests/bugs/1219985-3.html | 16 ++++++++++++ layout/reftests/bugs/1219985-4.html | 17 +++++++++++++ layout/reftests/bugs/1219985-5.html | 17 +++++++++++++ layout/reftests/bugs/1219985-6.html | 16 ++++++++++++ layout/reftests/bugs/1219985-7.html | 17 +++++++++++++ layout/reftests/bugs/1219985-8.html | 17 +++++++++++++ .../bugs/1219985-ref-opaque-clear.html | 5 ++++ .../1219985-ref-opaque-with-rendering.html | 7 ++++++ .../bugs/1219985-ref-transparent-clear.html | 5 ++++ ...219985-ref-transparent-with-rendering.html | 7 ++++++ layout/reftests/bugs/reftest.list | 8 ++++++ 20 files changed, 211 insertions(+), 17 deletions(-) create mode 100644 layout/reftests/bugs/1219985-1.html create mode 100644 layout/reftests/bugs/1219985-2.html create mode 100644 layout/reftests/bugs/1219985-3.html create mode 100644 layout/reftests/bugs/1219985-4.html create mode 100644 layout/reftests/bugs/1219985-5.html create mode 100644 layout/reftests/bugs/1219985-6.html create mode 100644 layout/reftests/bugs/1219985-7.html create mode 100644 layout/reftests/bugs/1219985-8.html create mode 100644 layout/reftests/bugs/1219985-ref-opaque-clear.html create mode 100644 layout/reftests/bugs/1219985-ref-opaque-with-rendering.html create mode 100644 layout/reftests/bugs/1219985-ref-transparent-clear.html create mode 100644 layout/reftests/bugs/1219985-ref-transparent-with-rendering.html diff --git a/dom/canvas/CanvasRenderingContext2D.cpp b/dom/canvas/CanvasRenderingContext2D.cpp index 140b86f8185c..3f71140b3864 100644 --- a/dom/canvas/CanvasRenderingContext2D.cpp +++ b/dom/canvas/CanvasRenderingContext2D.cpp @@ -1085,7 +1085,10 @@ CanvasRenderingContext2D::CanvasRenderingContext2D(layers::LayersBackend aCompos , mCompositorBackend(aCompositorBackend) // these are the default values from the Canvas spec , mWidth(0), mHeight(0) - , mZero(false), mOpaque(false) + , mZero(false) + , mOpaqueAttrValue(false) + , mContextAttributesHasAlpha(true) + , mOpaque(false) , mResetLayer(true) , mIPC(false) , mIsSkiaGL(false) @@ -1995,14 +1998,21 @@ CanvasRenderingContext2D::InitializeWithDrawTarget(nsIDocShell* aShell, } void -CanvasRenderingContext2D::SetIsOpaque(bool aIsOpaque) +CanvasRenderingContext2D::SetOpaqueValueFromOpaqueAttr(bool aOpaqueAttrValue) { - if (aIsOpaque != mOpaque) { - mOpaque = aIsOpaque; - ClearTarget(); + if (aOpaqueAttrValue != mOpaqueAttrValue) { + mOpaqueAttrValue = aOpaqueAttrValue; + UpdateIsOpaque(); } } +void +CanvasRenderingContext2D::UpdateIsOpaque() +{ + mOpaque = !mContextAttributesHasAlpha || mOpaqueAttrValue; + ClearTarget(); +} + NS_IMETHODIMP CanvasRenderingContext2D::SetIsIPC(bool aIsIPC) { @@ -2043,9 +2053,8 @@ CanvasRenderingContext2D::SetContextOptions(JSContext* aCx, } } - if (!attributes.mAlpha) { - SetIsOpaque(true); - } + mContextAttributesHasAlpha = attributes.mAlpha; + UpdateIsOpaque(); return NS_OK; } diff --git a/dom/canvas/CanvasRenderingContext2D.h b/dom/canvas/CanvasRenderingContext2D.h index f39b43632169..fd05d606b1d6 100644 --- a/dom/canvas/CanvasRenderingContext2D.h +++ b/dom/canvas/CanvasRenderingContext2D.h @@ -460,7 +460,7 @@ public: return mTarget->Snapshot(); } - virtual void SetIsOpaque(bool aIsOpaque) override; + virtual void SetOpaqueValueFromOpaqueAttr(bool aOpaqueAttrValue) override; bool GetIsOpaque() override { return mOpaque; } NS_IMETHOD Reset() override; already_AddRefed GetCanvasLayer(nsDisplayListBuilder* aBuilder, @@ -619,6 +619,9 @@ protected: // Returns whether the font was successfully updated. bool SetFontInternal(const nsAString& aFont, mozilla::ErrorResult& aError); + // Clears the target and updates mOpaque based on mOpaqueAttrValue and + // mContextAttributesHasAlpha. + void UpdateIsOpaque(); /** * Creates the error target, if it doesn't exist @@ -764,6 +767,17 @@ protected: // specific behavior on some operations. bool mZero; + // The two ways to set the opaqueness of the canvas. + // mOpaqueAttrValue: Whether the element has the moz-opaque attribute + // set. Can change during the lifetime of the context. Non-standard, should + // hopefully go away soon. + // mContextAttributesHasAlpha: The standard way of setting canvas opaqueness. + // Set at context initialization time and never changes. + bool mOpaqueAttrValue; + bool mContextAttributesHasAlpha; + + // Determines the context's opaqueness. Is computed from mOpaqueAttrValue and + // mContextAttributesHasAlpha in UpdateIsOpaque(). bool mOpaque; // This is true when the next time our layer is retrieved we need to diff --git a/dom/canvas/CanvasRenderingContextHelper.cpp b/dom/canvas/CanvasRenderingContextHelper.cpp index 405de1c7bae1..b66f6c4d0cf5 100644 --- a/dom/canvas/CanvasRenderingContextHelper.cpp +++ b/dom/canvas/CanvasRenderingContextHelper.cpp @@ -231,7 +231,7 @@ CanvasRenderingContextHelper::UpdateContext(JSContext* aCx, nsCOMPtr currentContext = mCurrentContext; - currentContext->SetIsOpaque(GetOpaqueAttr()); + currentContext->SetOpaqueValueFromOpaqueAttr(GetOpaqueAttr()); nsresult rv = currentContext->SetContextOptions(aCx, aNewContextOptions, aRvForDictionaryInit); diff --git a/dom/canvas/ImageBitmapRenderingContext.cpp b/dom/canvas/ImageBitmapRenderingContext.cpp index fe42beb6b089..b923d04cd509 100644 --- a/dom/canvas/ImageBitmapRenderingContext.cpp +++ b/dom/canvas/ImageBitmapRenderingContext.cpp @@ -189,8 +189,9 @@ ImageBitmapRenderingContext::GetSurfaceSnapshot(gfxAlphaType* const aOutAlphaTyp } void -ImageBitmapRenderingContext::SetIsOpaque(bool aIsOpaque) +ImageBitmapRenderingContext::SetOpaqueValueFromOpaqueAttr(bool aOpaqueAttrValue) { + // ignored } bool diff --git a/dom/canvas/ImageBitmapRenderingContext.h b/dom/canvas/ImageBitmapRenderingContext.h index aacfa7b80c43..6abbb46e2613 100644 --- a/dom/canvas/ImageBitmapRenderingContext.h +++ b/dom/canvas/ImageBitmapRenderingContext.h @@ -66,7 +66,7 @@ public: virtual already_AddRefed GetSurfaceSnapshot(gfxAlphaType* aOutAlphaType) override; - virtual void SetIsOpaque(bool aIsOpaque) override; + virtual void SetOpaqueValueFromOpaqueAttr(bool aOpaqueAttrValue) override; virtual bool GetIsOpaque() override; NS_IMETHOD Reset() override; virtual already_AddRefed GetCanvasLayer(nsDisplayListBuilder* aBuilder, diff --git a/dom/canvas/WebGLContext.h b/dom/canvas/WebGLContext.h index 79d350ba3b4d..e60568a230ea 100644 --- a/dom/canvas/WebGLContext.h +++ b/dom/canvas/WebGLContext.h @@ -380,7 +380,7 @@ public: virtual already_AddRefed GetSurfaceSnapshot(gfxAlphaType* out_alphaType) override; - virtual void SetIsOpaque(bool) override {}; + virtual void SetOpaqueValueFromOpaqueAttr(bool) override {}; bool GetIsOpaque() override { return !mOptions.alpha; } NS_IMETHOD SetContextOptions(JSContext* cx, JS::Handle options, diff --git a/dom/canvas/nsICanvasRenderingContextInternal.h b/dom/canvas/nsICanvasRenderingContextInternal.h index f3ee255341fe..b9f5256a24c1 100644 --- a/dom/canvas/nsICanvasRenderingContextInternal.h +++ b/dom/canvas/nsICanvasRenderingContextInternal.h @@ -126,11 +126,16 @@ public: virtual already_AddRefed GetSurfaceSnapshot(gfxAlphaType* out_alphaType = nullptr) = 0; - // If this context is opaque, the backing store of the canvas should + // If this is called with true, the backing store of the canvas should // be created as opaque; all compositing operators should assume the - // dst alpha is always 1.0. If this is never called, the context - // defaults to false (not opaque). - virtual void SetIsOpaque(bool isOpaque) = 0; + // dst alpha is always 1.0. If this is never called, the context's + // opaqueness is determined by the context attributes that it's initialized + // with. + virtual void SetOpaqueValueFromOpaqueAttr(bool aOpaqueAttrValue) = 0; + + // Returns whether the context is opaque. This value can be based both on + // the value of the moz-opaque attribute and on the context's initialization + // attributes. virtual bool GetIsOpaque() = 0; // Invalidate this context and release any held resources, in preperation diff --git a/layout/reftests/bugs/1219985-1.html b/layout/reftests/bugs/1219985-1.html new file mode 100644 index 000000000000..da68e0cbb9fc --- /dev/null +++ b/layout/reftests/bugs/1219985-1.html @@ -0,0 +1,16 @@ + + +Bug 1219985: Basic transparent rendering + +
+ +
+ + diff --git a/layout/reftests/bugs/1219985-2.html b/layout/reftests/bugs/1219985-2.html new file mode 100644 index 000000000000..f807a7db00ba --- /dev/null +++ b/layout/reftests/bugs/1219985-2.html @@ -0,0 +1,17 @@ + + +Bug 1219985: Setting the canvas size should clear the canvas + +
+ +
+ + diff --git a/layout/reftests/bugs/1219985-3.html b/layout/reftests/bugs/1219985-3.html new file mode 100644 index 000000000000..e2368bc76f73 --- /dev/null +++ b/layout/reftests/bugs/1219985-3.html @@ -0,0 +1,16 @@ + + +Bug 1219985: Basic rendering into a non-alpha canvas + +
+ +
+ + diff --git a/layout/reftests/bugs/1219985-4.html b/layout/reftests/bugs/1219985-4.html new file mode 100644 index 000000000000..fbdacec52858 --- /dev/null +++ b/layout/reftests/bugs/1219985-4.html @@ -0,0 +1,17 @@ + + +Bug 1219985: Setting the canvas size on a non-alpha should clear the canvas to opaque black + +
+ +
+ + diff --git a/layout/reftests/bugs/1219985-5.html b/layout/reftests/bugs/1219985-5.html new file mode 100644 index 000000000000..c00651d18eb0 --- /dev/null +++ b/layout/reftests/bugs/1219985-5.html @@ -0,0 +1,17 @@ + + +Bug 1219985: Only the context attributes from the first getContext call should be respected. + +
+ +
+ + diff --git a/layout/reftests/bugs/1219985-6.html b/layout/reftests/bugs/1219985-6.html new file mode 100644 index 000000000000..d75975854974 --- /dev/null +++ b/layout/reftests/bugs/1219985-6.html @@ -0,0 +1,16 @@ + + +Bug 1219985: moz-opaque should have the same effect as alpha:false + +
+ +
+ + diff --git a/layout/reftests/bugs/1219985-7.html b/layout/reftests/bugs/1219985-7.html new file mode 100644 index 000000000000..bef8e0f1eefc --- /dev/null +++ b/layout/reftests/bugs/1219985-7.html @@ -0,0 +1,17 @@ + + +Bug 1219985: Unsetting moz-opaque should clear the canvas + +
+ +
+ + diff --git a/layout/reftests/bugs/1219985-8.html b/layout/reftests/bugs/1219985-8.html new file mode 100644 index 000000000000..9747ec6d564c --- /dev/null +++ b/layout/reftests/bugs/1219985-8.html @@ -0,0 +1,17 @@ + + +Bug 1219985: Unsetting moz-opaque should clear the canvas even if the canvas has been created with alpha:false, and the canvas should stay opaque. + +
+ +
+ + diff --git a/layout/reftests/bugs/1219985-ref-opaque-clear.html b/layout/reftests/bugs/1219985-ref-opaque-clear.html new file mode 100644 index 000000000000..6bc9a437056e --- /dev/null +++ b/layout/reftests/bugs/1219985-ref-opaque-clear.html @@ -0,0 +1,5 @@ + + +Bug 1219985: Reference for an opaque canvas with nothing rendered in it + +
diff --git a/layout/reftests/bugs/1219985-ref-opaque-with-rendering.html b/layout/reftests/bugs/1219985-ref-opaque-with-rendering.html new file mode 100644 index 000000000000..a1915c77a6ad --- /dev/null +++ b/layout/reftests/bugs/1219985-ref-opaque-with-rendering.html @@ -0,0 +1,7 @@ + + +Bug 1219985: Reference for an opaque canvas with a green square rendered in it + +
+
+
diff --git a/layout/reftests/bugs/1219985-ref-transparent-clear.html b/layout/reftests/bugs/1219985-ref-transparent-clear.html new file mode 100644 index 000000000000..98290efbbb01 --- /dev/null +++ b/layout/reftests/bugs/1219985-ref-transparent-clear.html @@ -0,0 +1,5 @@ + + +Bug 1219985: Reference for a regular (non-opaque) canvas with nothing rendered in it. The red background behind the canvas is visible. + +
diff --git a/layout/reftests/bugs/1219985-ref-transparent-with-rendering.html b/layout/reftests/bugs/1219985-ref-transparent-with-rendering.html new file mode 100644 index 000000000000..a5205c90f230 --- /dev/null +++ b/layout/reftests/bugs/1219985-ref-transparent-with-rendering.html @@ -0,0 +1,7 @@ + + +Bug 1219985: Reference for a regular (non-opaque) canvas with a green square rendered in it. The red background behind the canvas is visible. + +
+
+
diff --git a/layout/reftests/bugs/reftest.list b/layout/reftests/bugs/reftest.list index c22722b03fef..272d8f76deb3 100644 --- a/layout/reftests/bugs/reftest.list +++ b/layout/reftests/bugs/reftest.list @@ -1959,6 +1959,14 @@ fuzzy-if(skiaContent,1,1) == 1202512-2.html 1202512-2-ref.html == 1209994-2.html 1209994-2-ref.html == 1209994-3.html 1209994-3-ref.html == 1209994-4.html 1209994-4-ref.html +== 1219985-1.html 1219985-ref-transparent-with-rendering.html +== 1219985-2.html 1219985-ref-transparent-clear.html +== 1219985-3.html 1219985-ref-opaque-with-rendering.html +== 1219985-4.html 1219985-ref-opaque-clear.html +== 1219985-5.html 1219985-ref-transparent-with-rendering.html +== 1219985-6.html 1219985-ref-opaque-with-rendering.html +== 1219985-7.html 1219985-ref-transparent-clear.html +== 1219985-8.html 1219985-ref-opaque-clear.html == 1222226-1.html 1222226-1-ref.html pref(layout.css.overflow-clip-box.enabled,true) == 1226278.html 1226278-ref.html == 1230466.html about:blank