Skip to content
Permalink
Browse files
Implement resizing options for ImageBitmap rendering
https://bugs.webkit.org/show_bug.cgi?id=178687
<rdar://problem/35135417>

Reviewed by Sam Weinig.

Source/WebCore:

Implement many of the sizing options for createImageBitmap.

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

* html/ImageBitmap.cpp:
(WebCore::croppedSourceRectangleWithFormatting):

    Implement the first bit of the algorithm from
    the HTML specification.

(WebCore::outputSizeForSourceRectangle):

    ... and then the second bit. Leave the rest in
    comments for now.

(WebCore::interpolationQualityForResizeQuality):

    Helper function to map ImageBitmapOptions to
    GraphicsContext.

(WebCore::ImageBitmap::createPromise):

    Implement more of the sizing algorithm.

* html/ImageBitmap.h: Origin tainting is defined to be false by default.

LayoutTests:

More ImageBitmap tests, this time focusing on sizing.

* http/wpt/2dcontext/imagebitmap/common.js:
(createCanvasOfSize):
(create9x9CanvasWith2dContext):
(create18x18CanvasWith2dContext):

    Helper functions.

* http/wpt/2dcontext/imagebitmap/createImageBitmap-sizing-expected.txt: Added.
* http/wpt/2dcontext/imagebitmap/createImageBitmap-sizing.html: Added.
* http/wpt/2dcontext/imagebitmap/drawImage-ImageBitmap.html:
* http/wpt/2dcontext/imagebitmap/resources/target-blue-dot-no-intrinsic.svg: Added.
* http/wpt/2dcontext/imagebitmap/resources/target-blue-dot.png: Renamed from LayoutTests/http/wpt/2dcontext/imagebitmap/target-blue-dot.png.
* http/wpt/2dcontext/imagebitmap/resources/target-blue-dot.svg: Added.

Canonical link: https://commits.webkit.org/194921@main
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@223925 268f45cc-cd09-0410-ab3c-d52691b4dbfc
  • Loading branch information
grorg committed Oct 24, 2017
1 parent 8fdf59a commit 6ade6bf2f8ef602210b81e16dfb4c34637176525
Showing 12 changed files with 454 additions and 46 deletions.
@@ -1,3 +1,27 @@
2017-10-24 Dean Jackson <dino@apple.com>

Implement resizing options for ImageBitmap rendering
https://bugs.webkit.org/show_bug.cgi?id=178687
<rdar://problem/35135417>

Reviewed by Sam Weinig.

More ImageBitmap tests, this time focusing on sizing.

* http/wpt/2dcontext/imagebitmap/common.js:
(createCanvasOfSize):
(create9x9CanvasWith2dContext):
(create18x18CanvasWith2dContext):

Helper functions.

* http/wpt/2dcontext/imagebitmap/createImageBitmap-sizing-expected.txt: Added.
* http/wpt/2dcontext/imagebitmap/createImageBitmap-sizing.html: Added.
* http/wpt/2dcontext/imagebitmap/drawImage-ImageBitmap.html:
* http/wpt/2dcontext/imagebitmap/resources/target-blue-dot-no-intrinsic.svg: Added.
* http/wpt/2dcontext/imagebitmap/resources/target-blue-dot.png: Renamed from LayoutTests/http/wpt/2dcontext/imagebitmap/target-blue-dot.png.
* http/wpt/2dcontext/imagebitmap/resources/target-blue-dot.svg: Added.

2017-10-24 Chris Dumez <cdumez@apple.com>

Add initial implementation for serviceWorker.postMessage()
@@ -57,10 +57,22 @@ function initializeImageData(imgData, width, height)
imgData.data[i * width * 4 + j * 4 + 2] = 255;
}

function createCanvasOfSize(width, height)
{
const c = document.createElement("canvas");
c.width = width;
c.height = height;
return c;
}

function create9x9CanvasWith2dContext()
{
let c = document.createElement("canvas");
c.width = 9;
c.height = 9;
const c = createCanvasOfSize(9, 9);
return [c, c.getContext("2d")];
}

function create18x18CanvasWith2dContext()
{
const c = createCanvasOfSize(18, 18);
return [c, c.getContext("2d")];
}
@@ -0,0 +1,11 @@

PASS createImageBitmap rejects with TypeError if resizeWidth is negative
PASS createImageBitmap rejects with TypeError if resizeHeight is negative
PASS createImageBitmap with cropped source
PASS createImageBitmap with a cropping rectangle that is bigger than the source
PASS createImageBitmap with resizeWidth and resizeHeight
PASS createImageBitmap with only resizeHeight should calculate resizeWidth
PASS createImageBitmap with only resizeWidth should calculate resizeHeight
PASS createImageBitmap with an SVG uses intrinsic size
PASS createImageBitmap with an SVG that has no intrinsic size uses resize parameters

@@ -0,0 +1,189 @@
<!DOCTYPE html>
<html>
<title>createImageBitmap with sizing test</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/common/canvas-tests.js"></script>
<script src="common.js"></script>
<link rel="stylesheet" href="/common/canvas-tests.css">
<body>
<script>
(function() {

// The ImageBitmap part of the HTML specification says this should be an InvalidStateError, but
// the IDL requires an unsigned value, so the TypeError will hit first.
promise_test(function(t) {
return promise_rejects(t, new TypeError, createImageBitmap(new Image(), 0, 0, 10, 10, { resizeWidth: -10, resizeHeight: 10 }));
}, "createImageBitmap rejects with TypeError if resizeWidth is negative");

promise_test(function(t) {
return promise_rejects(t, new TypeError, createImageBitmap(new Image(), 0, 0, 10, 10, { resizeWidth: 10, resizeHeight: -10 }));
}, "createImageBitmap rejects with TypeError if resizeHeight is negative");

promise_test(function() {
return new Promise(function(resolve, reject) {
let img = new Image();
img.onload = function() { resolve(img); };
img.src = "resources/target-blue-dot.png";
}).then(function(img) {
// Crop the 9x9 image into 5x5.
return createImageBitmap(img, 0, 0, 5, 5);
}).then(function(imageBitmap) {
assert_equals(imageBitmap.width, 5, "ImageBitmap width should be 5");
assert_equals(imageBitmap.height, 5, "ImageBitmap height should be 5");

let [canvas, ctx] = create9x9CanvasWith2dContext();
ctx.drawImage(imageBitmap, 0, 0);
_assertPixel(canvas, 0,0, 0,255,0,255, "0,0", "0,255,0,255");
_assertPixel(canvas, 4,3, 0,255,0,255, "4,3", "0,255,0,255");
_assertPixel(canvas, 3,4, 0,255,0,255, "3,4", "0,255,0,255");
_assertPixel(canvas, 4,4, 0,0,255,255, "4,4", "0,0,255,255"); // Target blue dot.
_assertPixel(canvas, 5,4, 0,0,0,0, "5,4", "0,0,0,0"); // Outside source rectangle so transparent.
_assertPixel(canvas, 4,5, 0,0,0,0, "4,5", "0,0,0,0"); // Outside source rectangle so transparent.
});
}, "createImageBitmap with cropped source");

promise_test(function() {
return new Promise(function(resolve, reject) {
let img = new Image();
img.onload = function() { resolve(img); };
img.src = "resources/target-blue-dot.png";
}).then(function(img) {
// Source is only 9x9, so the 100x100 will be clamped.
return createImageBitmap(img, 0, 0, 100, 100);
}).then(function(imageBitmap) {
assert_equals(imageBitmap.width, 9, "ImageBitmap width should be 9");
assert_equals(imageBitmap.height, 9, "ImageBitmap height should be 9");

let [canvas, ctx] = create9x9CanvasWith2dContext();
ctx.drawImage(imageBitmap, 0, 0);
_assertPixel(canvas, 0,0, 0,255,0,255, "0,0", "0,255,0,255");
_assertPixel(canvas, 4,3, 0,255,0,255, "4,3", "0,255,0,255");
_assertPixel(canvas, 3,4, 0,255,0,255, "3,4", "0,255,0,255");
_assertPixel(canvas, 4,4, 0,0,255,255, "4,4", "0,0,255,255"); // Target blue dot.
_assertPixel(canvas, 5,4, 0,255,0,255, "5,4", "0,255,0,255");
_assertPixel(canvas, 4,5, 0,255,0,255, "4,5", "0,255,0,255");
});
}, "createImageBitmap with a cropping rectangle that is bigger than the source");

promise_test(function() {
return new Promise(function(resolve, reject) {
let img = new Image();
img.onload = function() { resolve(img); };
img.src = "resources/target-blue-dot.png";
}).then(function(img) {
// Resize the 9x9 into 18x18, but without interpolation so that
// we can still do accurate pixel tests.
return createImageBitmap(img, 0, 0, 9, 9, { resizeWidth: 18, resizeHeight: 18, resizeQuality: "pixelated" });
}).then(function(imageBitmap) {
assert_equals(imageBitmap.width, 18, "ImageBitmap width should be 18");
assert_equals(imageBitmap.height, 18, "ImageBitmap height should be 18");

let [canvas, ctx] = create18x18CanvasWith2dContext();
ctx.drawImage(imageBitmap, 0, 0);
// All the target points are now 2x what they would be normally.
_assertPixel(canvas, 0,0, 0,255,0,255, "0,0", "0,255,0,255");
_assertPixel(canvas, 8,6, 0,255,0,255, "8,6", "0,255,0,255");
_assertPixel(canvas, 6,8, 0,255,0,255, "6,8", "0,255,0,255");
_assertPixel(canvas, 8,8, 0,0,255,255, "8,8", "0,0,255,255"); // Target blue dot.
_assertPixel(canvas, 9,9, 0,0,255,255, "9,9", "0,0,255,255"); // Target blue dot.
_assertPixel(canvas, 10,8, 0,255,0,255, "10,8", "0,255,0,255");
_assertPixel(canvas, 8,10, 0,255,0,255, "8,10", "0,255,0,255");

});
}, "createImageBitmap with resizeWidth and resizeHeight");

promise_test(function() {
return new Promise(function(resolve, reject) {
let img = new Image();
img.onload = function() { resolve(img); };
img.src = "resources/target-blue-dot.png";
}).then(function(img) {
// Only provide resizeHeight.
return createImageBitmap(img, 0, 0, 9, 9, { resizeHeight: 18, resizeQuality: "pixelated" });
}).then(function(imageBitmap) {
assert_equals(imageBitmap.width, 18, "ImageBitmap width should be 18");
assert_equals(imageBitmap.height, 18, "ImageBitmap height should be 18");

let [canvas, ctx] = create18x18CanvasWith2dContext();
ctx.drawImage(imageBitmap, 0, 0);
// All the target points are now 2x what they would be normally.
_assertPixel(canvas, 0,0, 0,255,0,255, "0,0", "0,255,0,255");
_assertPixel(canvas, 8,6, 0,255,0,255, "8,6", "0,255,0,255");
_assertPixel(canvas, 6,8, 0,255,0,255, "6,8", "0,255,0,255");
_assertPixel(canvas, 8,8, 0,0,255,255, "8,8", "0,0,255,255"); // Target blue dot.
_assertPixel(canvas, 9,9, 0,0,255,255, "9,9", "0,0,255,255"); // Target blue dot.
_assertPixel(canvas, 10,8, 0,255,0,255, "10,8", "0,255,0,255");
_assertPixel(canvas, 8,10, 0,255,0,255, "8,10", "0,255,0,255");

});
}, "createImageBitmap with only resizeHeight should calculate resizeWidth");

promise_test(function() {
return new Promise(function(resolve, reject) {
let img = new Image();
img.onload = function() { resolve(img); };
img.src = "resources/target-blue-dot.png";
}).then(function(img) {
// Only provide resizeWidth.
return createImageBitmap(img, 0, 0, 9, 9, { resizeWidth: 18, resizeQuality: "pixelated" });
}).then(function(imageBitmap) {
assert_equals(imageBitmap.width, 18, "ImageBitmap width should be 18");
assert_equals(imageBitmap.height, 18, "ImageBitmap height should be 18");

let [canvas, ctx] = create18x18CanvasWith2dContext();
ctx.drawImage(imageBitmap, 0, 0);
// All the target points are now 2x what they would be normally.
_assertPixel(canvas, 0,0, 0,255,0,255, "0,0", "0,255,0,255");
_assertPixel(canvas, 8,6, 0,255,0,255, "8,6", "0,255,0,255");
_assertPixel(canvas, 6,8, 0,255,0,255, "6,8", "0,255,0,255");
_assertPixel(canvas, 8,8, 0,0,255,255, "8,8", "0,0,255,255"); // Target blue dot.
_assertPixel(canvas, 9,9, 0,0,255,255, "9,9", "0,0,255,255"); // Target blue dot.
_assertPixel(canvas, 10,8, 0,255,0,255, "10,8", "0,255,0,255");
_assertPixel(canvas, 8,10, 0,255,0,255, "8,10", "0,255,0,255");

});
}, "createImageBitmap with only resizeWidth should calculate resizeHeight");

promise_test(function() {
return new Promise(function(resolve, reject) {
let img = new Image();
img.onload = function() { resolve(img); };
img.src = "resources/target-blue-dot.svg";
}).then(function(img) {
return createImageBitmap(img);
}).then(function(imageBitmap) {
let [canvas, ctx] = create9x9CanvasWith2dContext();
ctx.drawImage(imageBitmap, 0, 0);
_assertPixel(canvas, 0,0, 0,255,0,255, "0,0", "0,255,0,255");
_assertPixel(canvas, 4,3, 0,255,0,255, "4,3", "0,255,0,255");
_assertPixel(canvas, 3,4, 0,255,0,255, "3,4", "0,255,0,255");
_assertPixel(canvas, 4,4, 0,0,255,255, "4,4", "0,0,255,255"); // Target blue dot.
_assertPixel(canvas, 5,4, 0,255,0,255, "5,4", "0,255,0,255");
_assertPixel(canvas, 4,5, 0,255,0,255, "4,5", "0,255,0,255");
});
}, "createImageBitmap with an SVG uses intrinsic size");

promise_test(function() {
return new Promise(function(resolve, reject) {
let img = new Image();
img.onload = function() { resolve(img); };
img.src = "resources/target-blue-dot-no-intrinsic.svg";
}).then(function(img) {
return createImageBitmap(img, { resizeWidth: 9, resizeHeight: 9 });
}).then(function(imageBitmap) {
let [canvas, ctx] = create9x9CanvasWith2dContext();
ctx.drawImage(imageBitmap, 0, 0);
_assertPixel(canvas, 0,0, 0,255,0,255, "0,0", "0,255,0,255");
_assertPixel(canvas, 4,3, 0,255,0,255, "4,3", "0,255,0,255");
_assertPixel(canvas, 3,4, 0,255,0,255, "3,4", "0,255,0,255");
_assertPixel(canvas, 4,4, 0,0,255,255, "4,4", "0,0,255,255"); // Target blue dot.
_assertPixel(canvas, 5,4, 0,255,0,255, "5,4", "0,255,0,255");
_assertPixel(canvas, 4,5, 0,255,0,255, "4,5", "0,255,0,255");
});
}, "createImageBitmap with an SVG that has no intrinsic size uses resize parameters");

})();
</script>
</body>
</html>
@@ -30,7 +30,7 @@

promise_test(function() {
return new Promise(function(resolve, reject) {
var img = new Image();
let img = new Image();
img.onload = function() { resolve(img); };
img.src = "/images/pattern.png";
}).then(function(img) {
@@ -43,7 +43,7 @@

promise_test(function() {
return new Promise(function(resolve, reject) {
var img = new Image();
let img = new Image();
img.onload = function() { resolve(img); };
img.src = "/images/pattern.png";
}).then(function(img) {

0 comments on commit 6ade6bf

Please sign in to comment.