Title: [223819] trunk
Revision
223819
Author
[email protected]
Date
2017-10-21 14:48:17 -0700 (Sat, 21 Oct 2017)

Log Message

createImageBitmap with basic HTMLImageElement
https://bugs.webkit.org/show_bug.cgi?id=178619
<rdar://problem/35104118>

Reviewed by Antoine Quint.

Source/WebCore:

Implement the basic infrastructure for creating
an ImageBitmap from an HTMLImageElement.

Test: http/wpt/2dcontext/imagebitmap/createImageBitmap.html

* html/ImageBitmap.cpp:
(WebCore::ImageBitmap::createPromise): Create the image buffer
and draw the image into its backing store.
* html/ImageBitmap.h:

LayoutTests:

Make a better test for createImageBitmap. This will be
submitted to Web Platform Tests.

* http/wpt/2dcontext/imagebitmap/createImageBitmap-expected.txt: Added.
* http/wpt/2dcontext/imagebitmap/createImageBitmap.html: Added.
* http/wpt/common/canvas-tests.css: Added.
* http/wpt/common/canvas-tests.js: Added.
* http/wpt/images/pattern.png: Added.

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (223818 => 223819)


--- trunk/LayoutTests/ChangeLog	2017-10-21 21:42:51 UTC (rev 223818)
+++ trunk/LayoutTests/ChangeLog	2017-10-21 21:48:17 UTC (rev 223819)
@@ -1,3 +1,20 @@
+2017-10-21  Dean Jackson  <[email protected]>
+
+        createImageBitmap with basic HTMLImageElement
+        https://bugs.webkit.org/show_bug.cgi?id=178619
+        <rdar://problem/35104118>
+
+        Reviewed by Antoine Quint.
+
+        Make a better test for createImageBitmap. This will be
+        submitted to Web Platform Tests.
+
+        * http/wpt/2dcontext/imagebitmap/createImageBitmap-expected.txt: Added.
+        * http/wpt/2dcontext/imagebitmap/createImageBitmap.html: Added.
+        * http/wpt/common/canvas-tests.css: Added.
+        * http/wpt/common/canvas-tests.js: Added.
+        * http/wpt/images/pattern.png: Added.
+
 2017-10-21  Antti Koivisto  <[email protected]>
 
         Support ::before/::after pseudo elements with display:contents

Added: trunk/LayoutTests/http/wpt/2dcontext/imagebitmap/createImageBitmap-expected.txt (0 => 223819)


--- trunk/LayoutTests/http/wpt/2dcontext/imagebitmap/createImageBitmap-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/http/wpt/2dcontext/imagebitmap/createImageBitmap-expected.txt	2017-10-21 21:48:17 UTC (rev 223819)
@@ -0,0 +1,9 @@
+
+PASS createImageBitmap rejects with RangeError if width is zero 
+PASS createImageBitmap rejects with RangeError if height is zero 
+PASS createImageBitmap rejects with RangeError if width is negative 
+PASS createImageBitmap rejects with RangeError if height is negative 
+PASS createImageBitmap rejects with InvalidStateError on an HTMLImageElement with no image data 
+PASS createImageBitmap from an HTMLImageElement with image data 
+PASS A closed ImageBitmap has zero width and height 
+
Property changes on: trunk/LayoutTests/http/wpt/2dcontext/imagebitmap/createImageBitmap-expected.txt
___________________________________________________________________

Added: svn:eol-style

+native \ No newline at end of property

Added: svn:keywords

+Date Revision \ No newline at end of property

Added: svn:mime-type

+text/plain \ No newline at end of property

Added: trunk/LayoutTests/http/wpt/2dcontext/imagebitmap/createImageBitmap.html (0 => 223819)


--- trunk/LayoutTests/http/wpt/2dcontext/imagebitmap/createImageBitmap.html	                        (rev 0)
+++ trunk/LayoutTests/http/wpt/2dcontext/imagebitmap/createImageBitmap.html	2017-10-21 21:48:17 UTC (rev 223819)
@@ -0,0 +1,61 @@
+<!DOCTYPE html>
+<html>
+<title>createImageBitmap test</title>
+<script src=""
+<script src=""
+<script src=""
+<link rel="stylesheet" href=""
+<body>
+<script>
+(function() {
+    promise_test(function(t) {
+        return promise_rejects(t, new RangeError, createImageBitmap(new Image(), 0, 0, 0, 10));
+    }, "createImageBitmap rejects with RangeError if width is zero");
+
+    promise_test(function(t) {
+        return promise_rejects(t, new RangeError, createImageBitmap(new Image(), 0, 0, 10, 0));
+    }, "createImageBitmap rejects with RangeError if height is zero");
+
+    promise_test(function(t) {
+        return promise_rejects(t, new RangeError, createImageBitmap(new Image(), 0, 0, -10, 10));
+    }, "createImageBitmap rejects with RangeError if width is negative");
+
+    promise_test(function(t) {
+        return promise_rejects(t, new RangeError, createImageBitmap(new Image(), 0, 0, 10, -10));
+    }, "createImageBitmap rejects with RangeError if height is negative");
+
+    promise_test(function(t) {
+        return promise_rejects(t, "InvalidStateError", createImageBitmap(new Image()));
+    }, "createImageBitmap rejects with InvalidStateError on an HTMLImageElement with no image data");
+
+    promise_test(function() {
+        return new Promise(function(resolve, reject) {
+            var img = new Image();
+            img._onload_ = function() { resolve(img); };
+            img.src = ""
+        }).then(function(img) {
+            return createImageBitmap(img);
+        }).then(function(imageBitmap) {
+            assert_equals(imageBitmap.width, 20, "ImageBitmap width should be 20");
+            assert_equals(imageBitmap.height, 20, "ImageBitmap height should be 20");
+        });
+    }, "createImageBitmap from an HTMLImageElement with image data");
+
+    promise_test(function() {
+        return new Promise(function(resolve, reject) {
+            var img = new Image();
+            img._onload_ = function() { resolve(img); };
+            img.src = ""
+        }).then(function(img) {
+            return createImageBitmap(img);
+        }).then(function(imageBitmap) {
+            imageBitmap.close();
+            assert_equals(imageBitmap.width, 0, "A closed ImageBitmap width should be 0");
+            assert_equals(imageBitmap.height, 0, "A closed ImageBitmap height should be 0");
+        });
+    }, "A closed ImageBitmap has zero width and height");
+
+})();
+</script>
+</body>
+</html>
Property changes on: trunk/LayoutTests/http/wpt/2dcontext/imagebitmap/createImageBitmap.html
___________________________________________________________________

Added: svn:eol-style

+native \ No newline at end of property

Added: svn:keywords

+Date Revision \ No newline at end of property

Added: svn:mime-type

+text/html \ No newline at end of property

Added: trunk/LayoutTests/http/wpt/common/canvas-tests.css (0 => 223819)


--- trunk/LayoutTests/http/wpt/common/canvas-tests.css	                        (rev 0)
+++ trunk/LayoutTests/http/wpt/common/canvas-tests.css	2017-10-21 21:48:17 UTC (rev 223819)
@@ -0,0 +1,134 @@
+html.fail {
+    background: #f66;
+}
+html.pass {
+    background: #6f6;
+}
+html.needs_check {
+    background: #99f;
+}
+
+body {
+    font-size: small;
+    font-family: sans-serif;
+    color: black;
+}
+
+a:link {
+    color: #00c;
+}
+a:visited {
+    color: #808;
+}
+
+body.framed {
+    font-size: x-small;
+}
+
+h1 {
+    font-size: larger;
+    margin: 0;
+    padding-left: 0.5em;
+    text-indent: -0.5em;
+}
+
+p {
+    margin: 0;
+}
+
+p.notes {
+    margin-bottom: 0.5em;
+    font-style: italic;
+}
+
+ul {
+    margin: 0;
+    margin-bottom: 0.5em;
+    padding: 0;
+    padding-left: 1em;
+}
+
+.refs {
+    font-style: italic;
+    margin-bottom: 0.5em;
+}
+
+.refs ul {
+    display: inline;
+    margin: 0;
+    padding: 0;
+}
+
+.refs li {
+    display: inline;
+    list-style-type: none;
+    margin: 0;
+    padding: 0;
+}
+
+canvas {
+    display: none;
+    visibility: hidden;
+    border: 2px #f0f solid;
+    background: url(../images/background.png);
+}
+
+img.expected {
+    display: none;
+    border: 2px #f0f solid;
+    background: url(../images/background.png);
+}
+
+iframe {
+    border: 2px #f0f solid;
+}
+
+.output {
+    display: none;
+}
+
+.show_output .output, .needs_check .output  {
+    display: block !important;
+    visibility: visible !important;
+}
+
+.show_output #show_output {
+    display: none;
+}
+
+.resource {
+    visibility: hidden;
+    height: 0;
+}
+
+.fallback {
+    font-size: 2em;
+    font-weight: bold;
+    color: #a00;
+}
+
+
+html.minimal body {
+    color: white;
+}
+html.fail.minimal {
+    background: #f00;
+}
+html.pass.minimal {
+    background: #080;
+}
+html.needs_check.minimal {
+    background: #008;
+}
+.minimal #d {
+    display: none !important;
+}
+.minimal .expectedtext {
+    visibility: hidden !important;
+}
+#passtext, #failtext {
+    display: none;
+}
+.minimal.pass #passtext, .minimal.fail #failtext {
+    display: block;
+}
Property changes on: trunk/LayoutTests/http/wpt/common/canvas-tests.css
___________________________________________________________________

Added: svn:eol-style

+native \ No newline at end of property

Added: svn:keywords

+Date Revision \ No newline at end of property

Added: svn:mime-type

+text/css \ No newline at end of property

Added: trunk/LayoutTests/http/wpt/common/canvas-tests.js (0 => 223819)


--- trunk/LayoutTests/http/wpt/common/canvas-tests.js	                        (rev 0)
+++ trunk/LayoutTests/http/wpt/common/canvas-tests.js	2017-10-21 21:48:17 UTC (rev 223819)
@@ -0,0 +1,105 @@
+function _valToString(val)
+{
+    if (val === undefined || val === null)
+        return '[' + typeof(val) + ']';
+    return val.toString() + '[' + typeof(val) + ']';
+}
+
+function _assert(cond, text)
+{
+    assert_true(!!cond, text);
+}
+
+function _assertSame(a, b, text_a, text_b)
+{
+    var msg = text_a + ' === ' + text_b + ' (got ' + _valToString(a) +
+              ', expected ' + _valToString(b) + ')';
+    assert_equals(a, b, msg);
+}
+
+function _assertDifferent(a, b, text_a, text_b)
+{
+    var msg = text_a + ' !== ' + text_b + ' (got ' + _valToString(a) +
+              ', expected not ' + _valToString(b) + ')';
+    assert_not_equals(a, b, msg);
+}
+
+
+function _getPixel(canvas, x,y)
+{
+    var ctx = canvas.getContext('2d');
+    var imgdata = ctx.getImageData(x, y, 1, 1);
+    return [ imgdata.data[0], imgdata.data[1], imgdata.data[2], imgdata.data[3] ];
+}
+
+function _assertPixel(canvas, x,y, r,g,b,a, pos, colour)
+{
+    var c = _getPixel(canvas, x,y);
+    assert_equals(c[0], r, 'Red channel of the pixel at (' + x + ', ' + y + ')');
+    assert_equals(c[1], g, 'Green channel of the pixel at (' + x + ', ' + y + ')');
+    assert_equals(c[2], b, 'Blue channel of the pixel at (' + x + ', ' + y + ')');
+    assert_equals(c[3], a, 'Alpha channel of the pixel at (' + x + ', ' + y + ')');
+}
+
+function _assertPixelApprox(canvas, x,y, r,g,b,a, pos, colour, tolerance)
+{
+    var c = _getPixel(canvas, x,y);
+    assert_approx_equals(c[0], r, tolerance, 'Red channel of the pixel at (' + x + ', ' + y + ')');
+    assert_approx_equals(c[1], g, tolerance, 'Green channel of the pixel at (' + x + ', ' + y + ')');
+    assert_approx_equals(c[2], b, tolerance, 'Blue channel of the pixel at (' + x + ', ' + y + ')');
+    assert_approx_equals(c[3], a, tolerance, 'Alpha channel of the pixel at (' + x + ', ' + y + ')');
+}
+
+function _addTest(testFn)
+{
+    var deferred = false;
+    window.deferTest = function () { deferred = true; };
+    on_event(window, "load", function()
+    {
+        t.step(function() {
+            var canvas = document.getElementById('c');
+            var ctx = canvas.getContext('2d');
+            t.step(testFn, window, canvas, ctx);
+        });
+
+        if (!deferred) {
+            t.done();
+        }
+    });
+}
+
+function _assertGreen(ctx, canvasWidth, canvasHeight)
+{
+    var testColor = function(d, idx, expected) {
+        assert_equals(d[idx], expected, "d[" + idx + "]", String(expected));
+    };
+    var imagedata = ctx.getImageData(0, 0, canvasWidth, canvasHeight);
+    var w = imagedata.width, h = imagedata.height, d = imagedata.data;
+    for (var i = 0; i < h; ++i) {
+        for (var j = 0; j < w; ++j) {
+            testColor(d, 4 * (w * i + j) + 0, 0);
+            testColor(d, 4 * (w * i + j) + 1, 255);
+            testColor(d, 4 * (w * i + j) + 2, 0);
+            testColor(d, 4 * (w * i + j) + 3, 255);
+        }
+    }
+}
+
+function addCrossOriginYellowImage()
+{
+    var img = new Image();
+    img.id = "yellow.png";
+    img.className = "resource";
+    img.src = "" + "/images/yellow.png";
+    document.body.appendChild(img);
+}
+
+function addCrossOriginRedirectYellowImage()
+{
+    var img = new Image();
+    img.id = "yellow.png";
+    img.className = "resource";
+    img.src = "" + "/common/redirect.py?location=" +
+        get_host_info().HTTP_REMOTE_ORIGIN + "/images/yellow.png";
+    document.body.appendChild(img);
+}
Property changes on: trunk/LayoutTests/http/wpt/common/canvas-tests.js
___________________________________________________________________

Added: svn:eol-style

+native \ No newline at end of property

Added: svn:keywords

+Date Revision \ No newline at end of property

Added: svn:mime-type

+text/plain \ No newline at end of property

Added: trunk/LayoutTests/http/wpt/images/pattern.png


(Binary files differ)
Index: trunk/LayoutTests/http/wpt/images/pattern.png =================================================================== --- trunk/LayoutTests/http/wpt/images/pattern.png 2017-10-21 21:42:51 UTC (rev 223818) +++ trunk/LayoutTests/http/wpt/images/pattern.png 2017-10-21 21:48:17 UTC (rev 223819) Property changes on: trunk/LayoutTests/http/wpt/images/pattern.png ___________________________________________________________________

Added: svn:mime-type

+image/png \ No newline at end of property

Modified: trunk/Source/WebCore/ChangeLog (223818 => 223819)


--- trunk/Source/WebCore/ChangeLog	2017-10-21 21:42:51 UTC (rev 223818)
+++ trunk/Source/WebCore/ChangeLog	2017-10-21 21:48:17 UTC (rev 223819)
@@ -1,3 +1,21 @@
+2017-10-21  Dean Jackson  <[email protected]>
+
+        createImageBitmap with basic HTMLImageElement
+        https://bugs.webkit.org/show_bug.cgi?id=178619
+        <rdar://problem/35104118>
+
+        Reviewed by Antoine Quint.
+
+        Implement the basic infrastructure for creating
+        an ImageBitmap from an HTMLImageElement.
+
+        Test: http/wpt/2dcontext/imagebitmap/createImageBitmap.html
+
+        * html/ImageBitmap.cpp:
+        (WebCore::ImageBitmap::createPromise): Create the image buffer
+        and draw the image into its backing store.
+        * html/ImageBitmap.h:
+
 2017-10-21  Antoine Quint  <[email protected]>
 
         [Web Animations] Add bindings to unified sources

Modified: trunk/Source/WebCore/html/ImageBitmap.cpp (223818 => 223819)


--- trunk/Source/WebCore/html/ImageBitmap.cpp	2017-10-21 21:42:51 UTC (rev 223818)
+++ trunk/Source/WebCore/html/ImageBitmap.cpp	2017-10-21 21:48:17 UTC (rev 223819)
@@ -32,6 +32,7 @@
 #include "ExceptionOr.h"
 #include "FileReaderLoader.h"
 #include "FileReaderLoaderClient.h"
+#include "GraphicsContext.h"
 #include "HTMLCanvasElement.h"
 #include "HTMLImageElement.h"
 #include "HTMLVideoElement.h"
@@ -41,11 +42,18 @@
 #include "IntRect.h"
 #include "JSImageBitmap.h"
 #include "LayoutSize.h"
+#include "RenderElement.h"
 #include "SharedBuffer.h"
 #include <wtf/StdLibExtras.h>
 
 namespace WebCore {
 
+#if PLATFORM(COCOA)
+static RenderingMode bufferRenderingMode = Accelerated;
+#else
+static RenderingMode bufferRenderingMode = Unaccelerated;
+#endif
+
 Ref<ImageBitmap> ImageBitmap::create()
 {
     return adoptRef(*new ImageBitmap);
@@ -69,6 +77,11 @@
         return;
     }
 
+    if (sw < 0 || sh < 0) {
+        promise.reject(RangeError, "Cannot create ImageBitmap with a negative width or height");
+        return;
+    }
+
     WTF::switchOn(source,
         [&] (auto& specificSource) {
             createPromise(scriptExecutionContext, specificSource, WTFMove(options), IntRect { sx, sy, sw, sh }, WTFMove(promise));
@@ -78,7 +91,6 @@
 
 void ImageBitmap::createPromise(ScriptExecutionContext&, RefPtr<HTMLImageElement>& imageElement, ImageBitmapOptions&& options, std::optional<IntRect> rect, ImageBitmap::Promise&& promise)
 {
-    UNUSED_PARAM(imageElement);
     UNUSED_PARAM(options);
     UNUSED_PARAM(rect);
 
@@ -85,6 +97,12 @@
     // 2. If image is not completely available, then return a promise rejected with
     // an "InvalidStateError" DOMException and abort these steps.
 
+    auto* cachedImage = imageElement->cachedImage();
+    if (!cachedImage || !imageElement->complete()) {
+        promise.reject(InvalidStateError, "Cannot create ImageBitmap that is not completely available");
+        return;
+    }
+
     // 3. If image's media data has no intrinsic dimensions (e.g. it's a vector graphic
     //    with no specified content size), and both or either of the resizeWidth and
     //    resizeHeight options are not specified, then return a promise rejected with
@@ -103,6 +121,7 @@
     //    abort these steps.
 
     // 7. Create a new ImageBitmap object.
+
     auto imageBitmap = create();
 
     // 8. Let the ImageBitmap object's bitmap data be a copy of image's media data, cropped to
@@ -111,13 +130,26 @@
     //    one that the format defines is to be used when animation is not supported or is disabled),
     //    or, if there is no such image, the first frame of the animation.
 
+    // FIXME: Move this into a separate function and handle the cropping/resizing.
+    auto bitmapData = ImageBuffer::create(FloatSize(imageElement->width(), imageElement->height()), bufferRenderingMode);
+
+    auto imageForRender = imageElement->cachedImage()->imageForRenderer(imageElement->renderer());
+    if (!imageForRender) {
+        promise.reject(InvalidStateError, "Cannot create ImageBitmap from image that can't be rendered");
+        return;
+    }
+    FloatRect drawRect(FloatPoint(), FloatSize(imageElement->width(), imageElement->height()));
+    bitmapData->context().drawImage(*imageForRender, drawRect, drawRect);
+
+    imageBitmap->m_bitmapData = WTFMove(bitmapData);
+
     // 9. If the origin of image's image is not the same origin as the origin specified by the
     //    entry settings object, then set the origin-clean flag of the ImageBitmap object's
     //    bitmap to false.
 
     // 10. Return a new promise, but continue running these steps in parallel.
+    // 11. Resolve the promise with the new ImageBitmap object as the value.
 
-    // 11. Resolve the promise with the new ImageBitmap object as the value.
     return promise.resolve(WTFMove(imageBitmap));
 }
 
@@ -146,6 +178,7 @@
     return promise.resolve(WTFMove(imageBitmap));
 }
 
+#if ENABLE(VIDEO)
 void ImageBitmap::createPromise(ScriptExecutionContext&, RefPtr<HTMLVideoElement>& videoElement, ImageBitmapOptions&& options, std::optional<IntRect> rect, ImageBitmap::Promise&& promise)
 {
     UNUSED_PARAM(videoElement);
@@ -177,6 +210,7 @@
     // 8. Resolve the promise with the new ImageBitmap object as the value.
     return promise.resolve(WTFMove(imageBitmap));
 }
+#endif
 
 void ImageBitmap::createPromise(ScriptExecutionContext&, RefPtr<ImageBitmap>& existingImageBitmap, ImageBitmapOptions&& options, std::optional<IntRect> rect, ImageBitmap::Promise&& promise)
 {

Modified: trunk/Source/WebCore/html/ImageBitmap.h (223818 => 223819)


--- trunk/Source/WebCore/html/ImageBitmap.h	2017-10-21 21:42:51 UTC (rev 223818)
+++ trunk/Source/WebCore/html/ImageBitmap.h	2017-10-21 21:48:17 UTC (rev 223819)
@@ -77,8 +77,10 @@
     ImageBitmap();
 
     static void createPromise(ScriptExecutionContext&, RefPtr<HTMLImageElement>&, ImageBitmapOptions&&, std::optional<IntRect>, Promise&&);
+#if ENABLE(VIDEO)
+    static void createPromise(ScriptExecutionContext&, RefPtr<HTMLVideoElement>&, ImageBitmapOptions&&, std::optional<IntRect>, Promise&&);
+#endif
     static void createPromise(ScriptExecutionContext&, RefPtr<HTMLCanvasElement>&, ImageBitmapOptions&&, std::optional<IntRect>, Promise&&);
-    static void createPromise(ScriptExecutionContext&, RefPtr<HTMLVideoElement>&, ImageBitmapOptions&&, std::optional<IntRect>, Promise&&);
     static void createPromise(ScriptExecutionContext&, RefPtr<ImageBitmap>&, ImageBitmapOptions&&, std::optional<IntRect>, Promise&&);
     static void createPromise(ScriptExecutionContext&, RefPtr<Blob>&, ImageBitmapOptions&&, std::optional<IntRect>, Promise&&);
     static void createPromise(ScriptExecutionContext&, RefPtr<ImageData>&, ImageBitmapOptions&&, std::optional<IntRect>, Promise&&);
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to