drawImage() clears the canvas if it's the source of the image and globalCompositeOper...
authorcommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 20 Feb 2019 22:28:13 +0000 (22:28 +0000)
committercommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 20 Feb 2019 22:28:13 +0000 (22:28 +0000)
https://bugs.webkit.org/show_bug.cgi?id=194746

Patch by Said Abou-Hallawa <sabouhallawa@apple.com> on 2019-02-20
Reviewed by Dean Jackson.

Source/WebCore:

Test: fast/canvas/canvas-drawImage-composite-copy.html

If the source canvas of drawImage() is the same as the destination and
globalCompositeOperation is set to "copy", copy the srcRect from the
canvas to a temporary buffer before calling clearCanvas() then drawImage
from this temporary buffer.

* html/canvas/CanvasRenderingContext2DBase.cpp:
(WebCore::CanvasRenderingContext2DBase::drawImage):
* platform/graphics/ImageBuffer.cpp:
(WebCore::ImageBuffer::copyRectToBuffer):
* platform/graphics/ImageBuffer.h:

LayoutTests:

* fast/canvas/canvas-drawImage-composite-copy-expected.html: Added.
* fast/canvas/canvas-drawImage-composite-copy.html: Added.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@241840 268f45cc-cd09-0410-ab3c-d52691b4dbfc

LayoutTests/ChangeLog
LayoutTests/fast/canvas/canvas-drawImage-composite-copy-expected.html [new file with mode: 0644]
LayoutTests/fast/canvas/canvas-drawImage-composite-copy.html [new file with mode: 0644]
Source/WebCore/ChangeLog
Source/WebCore/html/canvas/CanvasRenderingContext2DBase.cpp
Source/WebCore/platform/graphics/ImageBuffer.cpp
Source/WebCore/platform/graphics/ImageBuffer.h

index c43d880..d894e78 100644 (file)
@@ -1,3 +1,13 @@
+2019-02-20  Said Abou-Hallawa  <sabouhallawa@apple.com>
+
+        drawImage() clears the canvas if it's the source of the image and globalCompositeOperation is "copy"
+        https://bugs.webkit.org/show_bug.cgi?id=194746
+
+        Reviewed by Dean Jackson.
+
+        * fast/canvas/canvas-drawImage-composite-copy-expected.html: Added.
+        * fast/canvas/canvas-drawImage-composite-copy.html: Added.
+
 2019-02-20  Shawn Roberts  <sroberts@apple.com>
 
         [ Mac WK2 ] REGRESSION (r231450) Layout Test http/tests/security/contentSecurityPolicy/block-all-mixed-content/insecure-image-in-iframe-with-enforced-and-report-policies.html is a flaky failure
diff --git a/LayoutTests/fast/canvas/canvas-drawImage-composite-copy-expected.html b/LayoutTests/fast/canvas/canvas-drawImage-composite-copy-expected.html
new file mode 100644 (file)
index 0000000..cb8a15d
--- /dev/null
@@ -0,0 +1,12 @@
+<body>
+    <canvas id="canvas" width="200" height="200"></canvas>
+    <script>
+        const canvas = document.getElementById("canvas");
+        const ctx = canvas.getContext("2d");
+        const width = canvas.width;
+        const height = canvas.height;
+
+        ctx.fillStyle = "green";
+        ctx.fillRect(0, 0, width / 2, height / 2);
+    </script>
+</body>
diff --git a/LayoutTests/fast/canvas/canvas-drawImage-composite-copy.html b/LayoutTests/fast/canvas/canvas-drawImage-composite-copy.html
new file mode 100644 (file)
index 0000000..f0be458
--- /dev/null
@@ -0,0 +1,21 @@
+<body>
+    <canvas id="canvas" width="200" height="200"></canvas>
+    <script>
+        const canvas = document.getElementById("canvas");
+        const ctx = canvas.getContext("2d");
+        const width = canvas.width;
+        const height = canvas.height;
+
+        ctx.fillStyle = "green";
+        ctx.fillRect(width / 2, height / 2, width / 2, height / 2);
+
+        ctx.globalCompositeOperation = "copy";
+        ctx.imageSmoothingEnabled = false;
+
+        ctx.drawImage(
+            canvas,
+            width / 2, height / 2, width / 2, height / 2,
+            0, 0, width / 2, height / 2
+        );
+    </script>
+</body>
index 0c12b27..b67cae8 100644 (file)
@@ -1,3 +1,23 @@
+2019-02-20  Said Abou-Hallawa  <sabouhallawa@apple.com>
+
+        drawImage() clears the canvas if it's the source of the image and globalCompositeOperation is "copy"
+        https://bugs.webkit.org/show_bug.cgi?id=194746
+
+        Reviewed by Dean Jackson.
+
+        Test: fast/canvas/canvas-drawImage-composite-copy.html
+
+        If the source canvas of drawImage() is the same as the destination and
+        globalCompositeOperation is set to "copy", copy the srcRect from the 
+        canvas to a temporary buffer before calling clearCanvas() then drawImage
+        from this temporary buffer.
+
+        * html/canvas/CanvasRenderingContext2DBase.cpp:
+        (WebCore::CanvasRenderingContext2DBase::drawImage):
+        * platform/graphics/ImageBuffer.cpp:
+        (WebCore::ImageBuffer::copyRectToBuffer):
+        * platform/graphics/ImageBuffer.h:
+
 2019-02-20  Simon Fraser  <simon.fraser@apple.com>
 
         REGRESSION (r241788>): ASSERTION FAILED: !m_normalFlowListDirty in TestWebKitAPI.WebKit.ResizeReversePaginatedWebView test
index d426fac..54b6d48 100644 (file)
@@ -1643,8 +1643,15 @@ ExceptionOr<void> CanvasRenderingContext2DBase::drawImage(HTMLCanvasElement& sou
         fullCanvasCompositedDrawImage(*buffer, dstRect, srcRect, state().globalComposite);
         didDrawEntireCanvas();
     } else if (state().globalComposite == CompositeCopy) {
-        clearCanvas();
-        c->drawImageBuffer(*buffer, dstRect, srcRect, ImagePaintingOptions(state().globalComposite, state().globalBlend));
+        if (&sourceCanvas == &canvasBase()) {
+            if (auto copy = buffer->copyRectToBuffer(srcRect, ColorSpaceSRGB, *c)) {
+                clearCanvas();
+                c->drawImageBuffer(*copy, dstRect, { { }, srcRect.size() }, ImagePaintingOptions(state().globalComposite, state().globalBlend));
+            }
+        } else {
+            clearCanvas();
+            c->drawImageBuffer(*buffer, dstRect, srcRect, ImagePaintingOptions(state().globalComposite, state().globalBlend));
+        }
         didDrawEntireCanvas();
     } else {
         c->drawImageBuffer(*buffer, dstRect, srcRect, ImagePaintingOptions(state().globalComposite, state().globalBlend));
index 8c302f5..3e33e61 100644 (file)
@@ -194,6 +194,21 @@ bool ImageBuffer::copyToPlatformTexture(GraphicsContext3D&, GC3Denum, Platform3D
 }
 #endif
 
+std::unique_ptr<ImageBuffer> ImageBuffer::copyRectToBuffer(const FloatRect& rect, ColorSpace colorSpace, const GraphicsContext& context)
+{
+    if (rect.isEmpty())
+        return nullptr;
+
+    IntSize scaledSize = ImageBuffer::compatibleBufferSize(rect.size(), context);
+
+    auto buffer = ImageBuffer::createCompatibleBuffer(scaledSize, 1, colorSpace, context);
+    if (!buffer)
+        return nullptr;
+
+    buffer->context().drawImageBuffer(*this, -rect.location());
+    return buffer;
+}
+
 std::unique_ptr<ImageBuffer> ImageBuffer::createCompatibleBuffer(const FloatSize& size, ColorSpace colorSpace, const GraphicsContext& context)
 {
     if (size.isEmpty())
index 0c03055..bd9e245 100644 (file)
@@ -71,6 +71,9 @@ public:
     WEBCORE_EXPORT static std::unique_ptr<ImageBuffer> create(const FloatSize&, RenderingMode, const GraphicsContext*, float resolutionScale = 1, ColorSpace = ColorSpaceSRGB, const HostWindow* = nullptr);
 #endif
 
+    // Create an image buffer compatible with the context and copy rect from this buffer into this new one.
+    std::unique_ptr<ImageBuffer> copyRectToBuffer(const FloatRect&, ColorSpace, const GraphicsContext&);
+
     // Create an image buffer compatible with the context, with suitable resolution for drawing into the buffer and then into this context.
     static std::unique_ptr<ImageBuffer> createCompatibleBuffer(const FloatSize&, const GraphicsContext&);
     static std::unique_ptr<ImageBuffer> createCompatibleBuffer(const FloatSize&, ColorSpace, const GraphicsContext&);