Rendering SVG images with same size as WebGL texture doesn't work correctly
https://bugs.webkit.org/show_bug.cgi?id=182367

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

Source/WebCore:

If am image buffer is created for a webgl texture and then it is reused
for another texture, it has to be cleared before drawing.

Test: webgl/webgl-texture-image-buffer-reuse.html

* html/canvas/WebGLRenderingContextBase.cpp:
(WebCore::WebGLRenderingContextBase::LRUImageBufferCache::imageBuffer):

LayoutTests:

* webgl/webgl-texture-image-buffer-reuse-expected.html: Added.
* webgl/webgl-texture-image-buffer-reuse.html: Added.

git-svn-id: http://svn.webkit.org/repository/webkit/trunk@228213 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/LayoutTests/ChangeLog b/LayoutTests/ChangeLog
index d04b60a..68a815c 100644
--- a/LayoutTests/ChangeLog
+++ b/LayoutTests/ChangeLog
@@ -1,3 +1,13 @@
+2018-02-06  Said Abou-Hallawa  <sabouhallawa@apple.com>
+
+        Rendering SVG images with same size as WebGL texture doesn't work correctly
+        https://bugs.webkit.org/show_bug.cgi?id=182367
+
+        Reviewed by Dean Jackson.
+
+        * webgl/webgl-texture-image-buffer-reuse-expected.html: Added.
+        * webgl/webgl-texture-image-buffer-reuse.html: Added.
+
 2018-02-06  Matt Lewis  <jlewis3@apple.com>
 
         Marked transitions/transition-display-property.html as flaky.
diff --git a/LayoutTests/webgl/webgl-texture-image-buffer-reuse-expected.html b/LayoutTests/webgl/webgl-texture-image-buffer-reuse-expected.html
new file mode 100644
index 0000000..aec216a
--- /dev/null
+++ b/LayoutTests/webgl/webgl-texture-image-buffer-reuse-expected.html
@@ -0,0 +1,17 @@
+<style>
+   canvas {
+       width: 100px;
+       height: 100px;
+       border: 1px solid green;
+   }
+</style>
+<body>
+    <p>Ensure if an image buffer is reused for a webgl texture, it will be cleared before drawing.</p>
+    <canvas width="100" height="100"/>
+    <script>
+        const canvas = document.querySelector('canvas');
+        const ctx = canvas.getContext('2d');
+        ctx.fillStyle = 'green';
+        ctx.fillRect(canvas.width / 4, canvas.height / 4, canvas.width / 2, canvas.height / 2);
+    </script>
+</body>
diff --git a/LayoutTests/webgl/webgl-texture-image-buffer-reuse.html b/LayoutTests/webgl/webgl-texture-image-buffer-reuse.html
new file mode 100644
index 0000000..f6e43bd
--- /dev/null
+++ b/LayoutTests/webgl/webgl-texture-image-buffer-reuse.html
@@ -0,0 +1,112 @@
+<style>
+    canvas {
+        width: 100px;
+        height: 100px;
+        border: 1px green solid;
+    }    
+</style>
+<body>
+    <p>Ensure if an image buffer is reused for a webgl texture, it will be cleared before drawing.</p>
+    <canvas width="100" height="100"></canvas>
+    <script>
+        (function() {
+            const canvas = document.querySelector('canvas');
+            const gl = canvas.getContext("webgl");
+            const program = createProgram(gl);
+            gl.useProgram(program);
+
+            createTextureBuffer(program, gl, new Float32Array([ 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1]), "a_texCoord");
+
+            const images = [
+                'data:image/svg+xml;charset=utf-8,<svg xmlns="http://www.w3.org/2000/svg" height="100" width="100"><rect width="100%" height="100%" fill="green"/></svg>',
+                'data:image/svg+xml;charset=utf-8,<svg xmlns="http://www.w3.org/2000/svg" height="100" width="100"><rect x="25%" y="25%" width="50%" height="50%" fill="green"/></svg>',
+            ];
+
+            const promises = [];
+            for (var index = 0; index < images.length; ++index)
+                promises.push(drawTexture(program, gl, images[index]));
+
+            if (window.testRunner) {
+                testRunner.waitUntilDone();
+                Promise.all(promises).then(() => {
+                    testRunner.notifyDone();
+                });
+            }
+        })();
+
+        function createProgram(gl) {
+            const vsSource = `
+                attribute vec4 a_position;
+                uniform vec2 u_resolution;
+                attribute vec2 a_texCoord;
+                varying vec2 v_texCoord;
+
+                void main() {
+                    gl_Position = a_position;
+                    v_texCoord = a_texCoord;
+                }
+            `;
+
+            const fsSource = `
+                precision mediump float;
+
+                uniform sampler2D u_sampler;
+                varying vec2 v_texCoord;
+
+                void main() {
+                    gl_FragColor = texture2D(u_sampler, v_texCoord);
+                } 
+            `;
+
+            const vertexShader = loadShader(gl, gl.VERTEX_SHADER, vsSource);
+            const fragmentShader = loadShader(gl, gl.FRAGMENT_SHADER, fsSource);
+
+            const program = gl.createProgram();
+            gl.attachShader(program, vertexShader);
+            gl.attachShader(program, fragmentShader);
+            gl.linkProgram(program);
+            return program;
+        }
+
+        function loadShader(gl, type, source) {
+            const shader = gl.createShader(type);
+            gl.shaderSource(shader, source);
+            gl.compileShader(shader);
+            return shader;
+        }
+
+        function drawTexture(program, gl, url) {
+            return loadTexture(gl, url).then(function() {
+                createTextureBuffer(program, gl, new Float32Array([-1, -1, 1, -1, -1, 1, -1, 1, 1, -1, 1, 1]), "a_position");
+                gl.drawArrays(gl.TRIANGLES, 0, 6);
+            });
+        }
+
+        function loadTexture(gl, url) {
+            return new Promise((resolve) => {
+                const image = new Image();
+                image.onload = function() {
+                    const texture = gl.createTexture();
+                    gl.bindTexture(gl.TEXTURE_2D, texture);
+                    gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image);
+                    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
+                    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
+                    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
+                    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
+                    resolve();
+                };
+                image.src = url;
+            });
+        }
+
+        function createTextureBuffer(program, gl, bufferData, positionAttribute) {
+            const buffer = gl.createBuffer();
+            gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
+            gl.bufferData(gl.ARRAY_BUFFER, bufferData, gl.STATIC_DRAW);
+
+            const positionLocation = gl.getAttribLocation(program, positionAttribute);
+            gl.enableVertexAttribArray(positionLocation);
+            gl.vertexAttribPointer(positionLocation, 2, gl.FLOAT, false, 0, 0);
+        }
+    </script>
+</body>
diff --git a/Source/WebCore/ChangeLog b/Source/WebCore/ChangeLog
index 2847f0e..c929766 100644
--- a/Source/WebCore/ChangeLog
+++ b/Source/WebCore/ChangeLog
@@ -1,3 +1,18 @@
+2018-02-06  Said Abou-Hallawa  <sabouhallawa@apple.com>
+
+        Rendering SVG images with same size as WebGL texture doesn't work correctly
+        https://bugs.webkit.org/show_bug.cgi?id=182367
+
+        Reviewed by Dean Jackson.
+
+        If am image buffer is created for a webgl texture and then it is reused 
+        for another texture, it has to be cleared before drawing.
+
+        Test: webgl/webgl-texture-image-buffer-reuse.html
+
+        * html/canvas/WebGLRenderingContextBase.cpp:
+        (WebCore::WebGLRenderingContextBase::LRUImageBufferCache::imageBuffer):
+
 2018-02-06  Youenn Fablet  <youenn@apple.com>
 
         Use downcast in createLinkPreloadResourceClient
diff --git a/Source/WebCore/html/canvas/WebGLRenderingContextBase.cpp b/Source/WebCore/html/canvas/WebGLRenderingContextBase.cpp
index 8fc871f..61031c4 100644
--- a/Source/WebCore/html/canvas/WebGLRenderingContextBase.cpp
+++ b/Source/WebCore/html/canvas/WebGLRenderingContextBase.cpp
@@ -5922,6 +5922,7 @@
         if (buf->logicalSize() != size)
             continue;
         bubbleToFront(i);
+        buf->context().clearRect(FloatRect({ }, FloatSize(size)));
         return buf;
     }