summaryrefslogtreecommitdiffstats
path: root/testing/web-platform/tests/html/canvas/tools/yaml-new/pixel-manipulation.yaml
diff options
context:
space:
mode:
Diffstat (limited to 'testing/web-platform/tests/html/canvas/tools/yaml-new/pixel-manipulation.yaml')
-rw-r--r--testing/web-platform/tests/html/canvas/tools/yaml-new/pixel-manipulation.yaml1042
1 files changed, 1042 insertions, 0 deletions
diff --git a/testing/web-platform/tests/html/canvas/tools/yaml-new/pixel-manipulation.yaml b/testing/web-platform/tests/html/canvas/tools/yaml-new/pixel-manipulation.yaml
new file mode 100644
index 0000000000..0643b047b1
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/tools/yaml-new/pixel-manipulation.yaml
@@ -0,0 +1,1042 @@
+- name: 2d.imageData.create2.basic
+ desc: createImageData(sw, sh) exists and returns something
+ code: |
+ @assert ctx.createImageData(1, 1) !== null;
+
+- name: 2d.imageData.create1.basic
+ desc: createImageData(imgdata) exists and returns something
+ code: |
+ @assert ctx.createImageData(ctx.createImageData(1, 1)) !== null;
+
+- name: 2d.imageData.create2.type
+ desc: createImageData(sw, sh) returns an ImageData object containing a Uint8ClampedArray
+ object
+ canvasType: ['HTMLCanvas']
+ code: |
+ @assert window.ImageData !== undefined;
+ @assert window.Uint8ClampedArray !== undefined;
+ window.ImageData.prototype.thisImplementsImageData = true;
+ window.Uint8ClampedArray.prototype.thisImplementsUint8ClampedArray = true;
+ var imgdata = ctx.createImageData(1, 1);
+ @assert imgdata.thisImplementsImageData;
+ @assert imgdata.data.thisImplementsUint8ClampedArray;
+
+- name: 2d.imageData.create1.type
+ desc: createImageData(imgdata) returns an ImageData object containing a Uint8ClampedArray
+ object
+ canvasType: ['HTMLCanvas']
+ code: |
+ @assert window.ImageData !== undefined;
+ @assert window.Uint8ClampedArray !== undefined;
+ window.ImageData.prototype.thisImplementsImageData = true;
+ window.Uint8ClampedArray.prototype.thisImplementsUint8ClampedArray = true;
+ var imgdata = ctx.createImageData(ctx.createImageData(1, 1));
+ @assert imgdata.thisImplementsImageData;
+ @assert imgdata.data.thisImplementsUint8ClampedArray;
+
+- name: 2d.imageData.create2.this
+ desc: createImageData(sw, sh) should throw when called with the wrong |this|
+ canvasType: ['HTMLCanvas']
+ notes: &bindings Defined in "Web IDL" (draft)
+ code: |
+ @assert throws TypeError CanvasRenderingContext2D.prototype.createImageData.call(null, 1, 1); @moz-todo
+ @assert throws TypeError CanvasRenderingContext2D.prototype.createImageData.call(undefined, 1, 1); @moz-todo
+ @assert throws TypeError CanvasRenderingContext2D.prototype.createImageData.call({}, 1, 1); @moz-todo
+
+- name: 2d.imageData.create1.this
+ desc: createImageData(imgdata) should throw when called with the wrong |this|
+ canvasType: ['HTMLCanvas']
+ notes: *bindings
+ code: |
+ var imgdata = ctx.createImageData(1, 1);
+ @assert throws TypeError CanvasRenderingContext2D.prototype.createImageData.call(null, imgdata); @moz-todo
+ @assert throws TypeError CanvasRenderingContext2D.prototype.createImageData.call(undefined, imgdata); @moz-todo
+ @assert throws TypeError CanvasRenderingContext2D.prototype.createImageData.call({}, imgdata); @moz-todo
+
+- name: 2d.imageData.create2.initial
+ desc: createImageData(sw, sh) returns transparent black data of the right size
+ code: |
+ var imgdata = ctx.createImageData(10, 20);
+ @assert imgdata.data.length === imgdata.width*imgdata.height*4;
+ @assert imgdata.width < imgdata.height;
+ @assert imgdata.width > 0;
+ var isTransparentBlack = true;
+ for (var i = 0; i < imgdata.data.length; ++i)
+ if (imgdata.data[i] !== 0)
+ isTransparentBlack = false;
+ @assert isTransparentBlack;
+
+- name: 2d.imageData.create1.initial
+ desc: createImageData(imgdata) returns transparent black data of the right size
+ code: |
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 100, 50);
+ var imgdata1 = ctx.getImageData(0, 0, 10, 20);
+ var imgdata2 = ctx.createImageData(imgdata1);
+ @assert imgdata2.data.length === imgdata1.data.length;
+ @assert imgdata2.width === imgdata1.width;
+ @assert imgdata2.height === imgdata1.height;
+ var isTransparentBlack = true;
+ for (var i = 0; i < imgdata2.data.length; ++i)
+ if (imgdata2.data[i] !== 0)
+ isTransparentBlack = false;
+ @assert isTransparentBlack;
+
+- name: 2d.imageData.create2.large
+ desc: createImageData(sw, sh) works for sizes much larger than the canvas
+ code: |
+ var imgdata = ctx.createImageData(1000, 2000);
+ @assert imgdata.data.length === imgdata.width*imgdata.height*4;
+ @assert imgdata.width < imgdata.height;
+ @assert imgdata.width > 0;
+ var isTransparentBlack = true;
+ for (var i = 0; i < imgdata.data.length; i += 7813) // check ~1024 points (assuming normal scaling)
+ if (imgdata.data[i] !== 0)
+ isTransparentBlack = false;
+ @assert isTransparentBlack;
+
+- name: 2d.imageData.create2.negative
+ desc: createImageData(sw, sh) takes the absolute magnitude of the size arguments
+ code: |
+ var imgdata1 = ctx.createImageData(10, 20);
+ var imgdata2 = ctx.createImageData(-10, 20);
+ var imgdata3 = ctx.createImageData(10, -20);
+ var imgdata4 = ctx.createImageData(-10, -20);
+ @assert imgdata1.data.length === imgdata2.data.length;
+ @assert imgdata2.data.length === imgdata3.data.length;
+ @assert imgdata3.data.length === imgdata4.data.length;
+
+- name: 2d.imageData.create2.zero
+ desc: createImageData(sw, sh) throws INDEX_SIZE_ERR if size is zero
+ code: |
+ @assert throws INDEX_SIZE_ERR ctx.createImageData(10, 0);
+ @assert throws INDEX_SIZE_ERR ctx.createImageData(0, 10);
+ @assert throws INDEX_SIZE_ERR ctx.createImageData(0, 0);
+ @assert throws INDEX_SIZE_ERR ctx.createImageData(0.99, 10);
+ @assert throws INDEX_SIZE_ERR ctx.createImageData(10, 0.1);
+
+- name: 2d.imageData.create2.nonfinite
+ desc: createImageData() throws TypeError if arguments are not finite
+ notes: *bindings
+ code: |
+ @nonfinite @assert throws TypeError ctx.createImageData(<10 Infinity -Infinity NaN>, <10 Infinity -Infinity NaN>);
+ var posinfobj = { valueOf: function() { return Infinity; } },
+ neginfobj = { valueOf: function() { return -Infinity; } },
+ nanobj = { valueOf: function() { return -Infinity; } };
+ @nonfinite @assert throws TypeError ctx.createImageData(<10 posinfobj neginfobj nanobj>, <10 posinfobj neginfobj nanobj>);
+
+- name: 2d.imageData.create1.zero
+ desc: createImageData(null) throws TypeError
+ code: |
+ @assert throws TypeError ctx.createImageData(null);
+
+- name: 2d.imageData.create2.double
+ desc: createImageData(w, h) double is converted to long
+ code: |
+ var imgdata1 = ctx.createImageData(10.01, 10.99);
+ var imgdata2 = ctx.createImageData(-10.01, -10.99);
+ @assert imgdata1.width === 10;
+ @assert imgdata1.height === 10;
+ @assert imgdata2.width === 10;
+ @assert imgdata2.height === 10;
+
+- name: 2d.imageData.get.double
+ desc: createImageData(w, h) double is converted to long
+ code: |
+ var imgdata1 = ctx.getImageData(0, 0, 10.01, 10.99);
+ var imgdata2 = ctx.getImageData(0, 0, -10.01, -10.99);
+ @assert imgdata1.width === 10;
+ @assert imgdata1.height === 10;
+ @assert imgdata2.width === 10;
+ @assert imgdata2.height === 10;
+
+- name: 2d.imageData.create2.round
+ desc: createImageData(w, h) is rounded the same as getImageData(0, 0, w, h)
+ code: |
+ var imgdata1 = ctx.createImageData(10.01, 10.99);
+ var imgdata2 = ctx.getImageData(0, 0, 10.01, 10.99);
+ @assert imgdata1.width === imgdata2.width;
+ @assert imgdata1.height === imgdata2.height;
+
+- name: 2d.imageData.create.and.resize
+ desc: Verify no crash when resizing an image bitmap to zero.
+ canvasType: ['HTMLCanvas']
+ images:
+ - red.png
+ code: |
+ var image = new Image();
+ image.onload = t.step_func(function() {
+ var options = { resizeHeight: 0 };
+ var p1 = createImageBitmap(image, options);
+ p1.catch(function(error){});
+ t.done();
+ });
+ image.src = 'red.png';
+
+- name: 2d.imageData.get.basic
+ desc: getImageData() exists and returns something
+ code: |
+ @assert ctx.getImageData(0, 0, 100, 50) !== null;
+
+- name: 2d.imageData.get.type
+ canvasType: ['HTMLCanvas']
+ desc: getImageData() returns an ImageData object containing a Uint8ClampedArray
+ object
+ code: |
+ @assert window.ImageData !== undefined;
+ @assert window.Uint8ClampedArray !== undefined;
+ window.ImageData.prototype.thisImplementsImageData = true;
+ window.Uint8ClampedArray.prototype.thisImplementsUint8ClampedArray = true;
+ var imgdata = ctx.getImageData(0, 0, 1, 1);
+ @assert imgdata.thisImplementsImageData;
+ @assert imgdata.data.thisImplementsUint8ClampedArray;
+
+- name: 2d.imageData.get.zero
+ desc: getImageData() throws INDEX_SIZE_ERR if size is zero
+ code: |
+ @assert throws INDEX_SIZE_ERR ctx.getImageData(1, 1, 10, 0);
+ @assert throws INDEX_SIZE_ERR ctx.getImageData(1, 1, 0, 10);
+ @assert throws INDEX_SIZE_ERR ctx.getImageData(1, 1, 0, 0);
+ @assert throws INDEX_SIZE_ERR ctx.getImageData(1, 1, 0.1, 10);
+ @assert throws INDEX_SIZE_ERR ctx.getImageData(1, 1, 10, 0.99);
+ @assert throws INDEX_SIZE_ERR ctx.getImageData(1, 1, -0.1, 10);
+ @assert throws INDEX_SIZE_ERR ctx.getImageData(1, 1, 10, -0.99);
+
+- name: 2d.imageData.get.nonfinite
+ desc: getImageData() throws TypeError if arguments are not finite
+ notes: *bindings
+ code: |
+ @nonfinite @assert throws TypeError ctx.getImageData(<10 Infinity -Infinity NaN>, <10 Infinity -Infinity NaN>, <10 Infinity -Infinity NaN>, <10 Infinity -Infinity NaN>);
+ var posinfobj = { valueOf: function() { return Infinity; } },
+ neginfobj = { valueOf: function() { return -Infinity; } },
+ nanobj = { valueOf: function() { return -Infinity; } };
+ @nonfinite @assert throws TypeError ctx.getImageData(<10 posinfobj neginfobj nanobj>, <10 posinfobj neginfobj nanobj>, <10 posinfobj neginfobj nanobj>, <10 posinfobj neginfobj nanobj>);
+
+- name: 2d.imageData.get.source.outside
+ desc: getImageData() returns transparent black outside the canvas
+ code: |
+ ctx.fillStyle = '#08f';
+ ctx.fillRect(0, 0, 100, 50);
+
+ var imgdata1 = ctx.getImageData(-10, 5, 1, 1);
+ @assert imgdata1.data[0] === 0;
+ @assert imgdata1.data[1] === 0;
+ @assert imgdata1.data[2] === 0;
+ @assert imgdata1.data[3] === 0;
+
+ var imgdata2 = ctx.getImageData(10, -5, 1, 1);
+ @assert imgdata2.data[0] === 0;
+ @assert imgdata2.data[1] === 0;
+ @assert imgdata2.data[2] === 0;
+ @assert imgdata2.data[3] === 0;
+
+ var imgdata3 = ctx.getImageData(200, 5, 1, 1);
+ @assert imgdata3.data[0] === 0;
+ @assert imgdata3.data[1] === 0;
+ @assert imgdata3.data[2] === 0;
+ @assert imgdata3.data[3] === 0;
+
+ var imgdata4 = ctx.getImageData(10, 60, 1, 1);
+ @assert imgdata4.data[0] === 0;
+ @assert imgdata4.data[1] === 0;
+ @assert imgdata4.data[2] === 0;
+ @assert imgdata4.data[3] === 0;
+
+ var imgdata5 = ctx.getImageData(100, 10, 1, 1);
+ @assert imgdata5.data[0] === 0;
+ @assert imgdata5.data[1] === 0;
+ @assert imgdata5.data[2] === 0;
+ @assert imgdata5.data[3] === 0;
+
+ var imgdata6 = ctx.getImageData(0, 10, 1, 1);
+ @assert imgdata6.data[0] === 0;
+ @assert imgdata6.data[1] === 136;
+ @assert imgdata6.data[2] === 255;
+ @assert imgdata6.data[3] === 255;
+
+ var imgdata7 = ctx.getImageData(-10, 10, 20, 20);
+ @assert imgdata7.data[ 0*4+0] === 0;
+ @assert imgdata7.data[ 0*4+1] === 0;
+ @assert imgdata7.data[ 0*4+2] === 0;
+ @assert imgdata7.data[ 0*4+3] === 0;
+ @assert imgdata7.data[ 9*4+0] === 0;
+ @assert imgdata7.data[ 9*4+1] === 0;
+ @assert imgdata7.data[ 9*4+2] === 0;
+ @assert imgdata7.data[ 9*4+3] === 0;
+ @assert imgdata7.data[10*4+0] === 0;
+ @assert imgdata7.data[10*4+1] === 136;
+ @assert imgdata7.data[10*4+2] === 255;
+ @assert imgdata7.data[10*4+3] === 255;
+ @assert imgdata7.data[19*4+0] === 0;
+ @assert imgdata7.data[19*4+1] === 136;
+ @assert imgdata7.data[19*4+2] === 255;
+ @assert imgdata7.data[19*4+3] === 255;
+ @assert imgdata7.data[20*4+0] === 0;
+ @assert imgdata7.data[20*4+1] === 0;
+ @assert imgdata7.data[20*4+2] === 0;
+ @assert imgdata7.data[20*4+3] === 0;
+
+- name: 2d.imageData.get.source.negative
+ desc: getImageData() works with negative width and height, and returns top-to-bottom
+ left-to-right
+ code: |
+ ctx.fillStyle = '#000';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.fillStyle = '#fff';
+ ctx.fillRect(20, 10, 60, 10);
+
+ var imgdata1 = ctx.getImageData(85, 25, -10, -10);
+ @assert imgdata1.data[0] === 255;
+ @assert imgdata1.data[1] === 255;
+ @assert imgdata1.data[2] === 255;
+ @assert imgdata1.data[3] === 255;
+ @assert imgdata1.data[imgdata1.data.length-4+0] === 0;
+ @assert imgdata1.data[imgdata1.data.length-4+1] === 0;
+ @assert imgdata1.data[imgdata1.data.length-4+2] === 0;
+ @assert imgdata1.data[imgdata1.data.length-4+3] === 255;
+
+ var imgdata2 = ctx.getImageData(0, 0, -1, -1);
+ @assert imgdata2.data[0] === 0;
+ @assert imgdata2.data[1] === 0;
+ @assert imgdata2.data[2] === 0;
+ @assert imgdata2.data[3] === 0;
+
+- name: 2d.imageData.get.source.size
+ desc: getImageData() returns bigger ImageData for bigger source rectangle
+ code: |
+ var imgdata1 = ctx.getImageData(0, 0, 10, 10);
+ var imgdata2 = ctx.getImageData(0, 0, 20, 20);
+ @assert imgdata2.width > imgdata1.width;
+ @assert imgdata2.height > imgdata1.height;
+
+- name: 2d.imageData.get.nonpremul
+ desc: getImageData() returns non-premultiplied colors
+ code: |
+ ctx.fillStyle = 'rgba(255, 255, 255, 0.5)';
+ ctx.fillRect(0, 0, 100, 50);
+ var imgdata = ctx.getImageData(10, 10, 10, 10);
+ @assert imgdata.data[0] > 200;
+ @assert imgdata.data[1] > 200;
+ @assert imgdata.data[2] > 200;
+ @assert imgdata.data[3] > 100;
+ @assert imgdata.data[3] < 200;
+
+- name: 2d.imageData.get.range
+ desc: getImageData() returns values in the range [0, 255]
+ code: |
+ ctx.fillStyle = '#000';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.fillStyle = '#fff';
+ ctx.fillRect(20, 10, 60, 10);
+ var imgdata1 = ctx.getImageData(10, 5, 1, 1);
+ @assert imgdata1.data[0] === 0;
+ var imgdata2 = ctx.getImageData(30, 15, 1, 1);
+ @assert imgdata2.data[0] === 255;
+
+- name: 2d.imageData.get.clamp
+ desc: getImageData() clamps colors to the range [0, 255]
+ code: |
+ ctx.fillStyle = 'rgb(-100, -200, -300)';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.fillStyle = 'rgb(256, 300, 400)';
+ ctx.fillRect(20, 10, 60, 10);
+ var imgdata1 = ctx.getImageData(10, 5, 1, 1);
+ @assert imgdata1.data[0] === 0;
+ @assert imgdata1.data[1] === 0;
+ @assert imgdata1.data[2] === 0;
+ var imgdata2 = ctx.getImageData(30, 15, 1, 1);
+ @assert imgdata2.data[0] === 255;
+ @assert imgdata2.data[1] === 255;
+ @assert imgdata2.data[2] === 255;
+
+- name: 2d.imageData.get.length
+ desc: getImageData() returns a correctly-sized Uint8ClampedArray
+ code: |
+ var imgdata = ctx.getImageData(0, 0, 10, 10);
+ @assert imgdata.data.length === imgdata.width*imgdata.height*4;
+
+- name: 2d.imageData.get.order.cols
+ desc: getImageData() returns leftmost columns first
+ code: |
+ ctx.fillStyle = '#fff';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.fillStyle = '#000';
+ ctx.fillRect(0, 0, 2, 50);
+ var imgdata = ctx.getImageData(0, 0, 10, 10);
+ @assert imgdata.data[0] === 0;
+ @assert imgdata.data[Math.round(imgdata.width/2*4)] === 255;
+ @assert imgdata.data[Math.round((imgdata.height/2)*imgdata.width*4)] === 0;
+
+- name: 2d.imageData.get.order.rows
+ desc: getImageData() returns topmost rows first
+ code: |
+ ctx.fillStyle = '#fff';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.fillStyle = '#000';
+ ctx.fillRect(0, 0, 100, 2);
+ var imgdata = ctx.getImageData(0, 0, 10, 10);
+ @assert imgdata.data[0] === 0;
+ @assert imgdata.data[Math.floor(imgdata.width/2*4)] === 0;
+ @assert imgdata.data[(imgdata.height/2)*imgdata.width*4] === 255;
+
+- name: 2d.imageData.get.order.rgb
+ desc: getImageData() returns R then G then B
+ code: |
+ ctx.fillStyle = '#48c';
+ ctx.fillRect(0, 0, 100, 50);
+ var imgdata = ctx.getImageData(0, 0, 10, 10);
+ @assert imgdata.data[0] === 0x44;
+ @assert imgdata.data[1] === 0x88;
+ @assert imgdata.data[2] === 0xCC;
+ @assert imgdata.data[3] === 255;
+ @assert imgdata.data[4] === 0x44;
+ @assert imgdata.data[5] === 0x88;
+ @assert imgdata.data[6] === 0xCC;
+ @assert imgdata.data[7] === 255;
+
+- name: 2d.imageData.get.order.alpha
+ desc: getImageData() returns A in the fourth component
+ code: |
+ ctx.fillStyle = 'rgba(0, 0, 0, 0.5)';
+ ctx.fillRect(0, 0, 100, 50);
+ var imgdata = ctx.getImageData(0, 0, 10, 10);
+ @assert imgdata.data[3] < 200;
+ @assert imgdata.data[3] > 100;
+
+- name: 2d.imageData.get.unaffected
+ desc: getImageData() is not affected by context state
+ code: |
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 50, 50)
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(50, 0, 50, 50)
+ ctx.save();
+ ctx.translate(50, 0);
+ ctx.globalAlpha = 0.1;
+ ctx.globalCompositeOperation = 'destination-atop';
+ ctx.shadowColor = '#f00';
+ ctx.rect(0, 0, 5, 5);
+ ctx.clip();
+ var imgdata = ctx.getImageData(0, 0, 50, 50);
+ ctx.restore();
+ ctx.putImageData(imgdata, 50, 0);
+ @assert pixel 25,25 ==~ 0,255,0,255;
+ @assert pixel 75,25 ==~ 0,255,0,255;
+ expected: green
+
+- name: 2d.imageData.get.large.crash
+ desc: Test that canvas crash when image data cannot be allocated.
+ code: |
+ @assert throws TypeError ctx.getImageData(10, 0xffffffff, 2147483647, 10);
+
+- name: 2d.imageData.get.rounding
+ desc: Test the handling of non-integer source coordinates in getImageData().
+ code: |
+ function testDimensions(sx, sy, sw, sh, width, height)
+ {
+ imageData = ctx.getImageData(sx, sy, sw, sh);
+ @assert imageData.width == width;
+ @assert imageData.height == height;
+ }
+
+ testDimensions(0, 0, 20, 10, 20, 10);
+
+ testDimensions(.1, .2, 20, 10, 20, 10);
+ testDimensions(.9, .8, 20, 10, 20, 10);
+
+ testDimensions(0, 0, 20.9, 10.9, 20, 10);
+ testDimensions(0, 0, 20.1, 10.1, 20, 10);
+
+ testDimensions(-1, -1, 20, 10, 20, 10);
+
+ testDimensions(-1.1, 0, 20, 10, 20, 10);
+ testDimensions(-1.9, 0, 20, 10, 20, 10);
+
+- name: 2d.imageData.get.invalid
+ desc: Verify getImageData() behavior in invalid cases.
+ code: |
+ imageData = ctx.getImageData(0,0,2,2);
+ var testValues = [NaN, true, false, "\"garbage\"", "-1",
+ "0", "1", "2", Infinity, -Infinity,
+ -5, -0.5, 0, 0.5, 5,
+ 5.4, 255, 256, null, undefined];
+ var testResults = [0, 1, 0, 0, 0,
+ 0, 1, 2, 255, 0,
+ 0, 0, 0, 0, 5,
+ 5, 255, 255, 0, 0];
+ for (var i = 0; i < testValues.length; i++) {
+ imageData.data[0] = testValues[i];
+ @assert imageData.data[0] == testResults[i];
+ }
+ imageData.data['foo']='garbage';
+ @assert imageData.data['foo'] == 'garbage';
+ imageData.data[-1]='garbage';
+ @assert imageData.data[-1] == undefined;
+ imageData.data[17]='garbage';
+ @assert imageData.data[17] == undefined;
+
+- name: 2d.imageData.object.properties
+ desc: ImageData objects have the right properties
+ code: |
+ var imgdata = ctx.getImageData(0, 0, 10, 10);
+ @assert typeof(imgdata.width) === 'number';
+ @assert typeof(imgdata.height) === 'number';
+ @assert typeof(imgdata.data) === 'object';
+
+- name: 2d.imageData.object.readonly
+ desc: ImageData objects properties are read-only
+ code: |
+ var imgdata = ctx.getImageData(0, 0, 10, 10);
+ var w = imgdata.width;
+ var h = imgdata.height;
+ var d = imgdata.data;
+ imgdata.width = 123;
+ imgdata.height = 123;
+ imgdata.data = [100,100,100,100];
+ @assert imgdata.width === w;
+ @assert imgdata.height === h;
+ @assert imgdata.data === d;
+ @assert imgdata.data[0] === 0;
+ @assert imgdata.data[1] === 0;
+ @assert imgdata.data[2] === 0;
+ @assert imgdata.data[3] === 0;
+
+- name: 2d.imageData.object.ctor.size
+ canvasType: ['HTMLCanvas']
+ desc: ImageData has a usable constructor
+ code: |
+ @assert window.ImageData !== undefined;
+
+ var imgdata = new window.ImageData(2, 3);
+ @assert imgdata.width === 2;
+ @assert imgdata.height === 3;
+ @assert imgdata.data.length === 2 * 3 * 4;
+ for (var i = 0; i < imgdata.data.length; ++i) {
+ @assert imgdata.data[i] === 0;
+ }
+
+- name: 2d.imageData.object.ctor.basics
+ canvasType: ['HTMLCanvas']
+ desc: Testing different type of ImageData constructor
+ code: |
+ function setRGBA(imageData, i, rgba)
+ {
+ var s = i * 4;
+ imageData[s] = rgba[0];
+ imageData[s + 1] = rgba[1];
+ imageData[s + 2] = rgba[2];
+ imageData[s + 3] = rgba[3];
+ }
+
+ function getRGBA(imageData, i)
+ {
+ var result = [];
+ var s = i * 4;
+ for (var j = 0; j < 4; j++) {
+ result[j] = imageData[s + j];
+ }
+ return result;
+ }
+
+ function assertArrayEquals(actual, expected)
+ {
+ @assert typeof actual === "object";
+ @assert actual !== null;
+ @assert "length" in actual === true;
+ @assert actual.length === expected.length;
+ for (var i = 0; i < actual.length; i++) {
+ @assert actual.hasOwnProperty(i) === expected.hasOwnProperty(i);
+ @assert actual[i] === expected[i];
+ }
+ }
+
+ @assert ImageData !== undefined;
+ imageData = new ImageData(100, 50);
+
+ @assert imageData !== null;
+ @assert imageData.data !== null;
+ @assert imageData.width === 100;
+ @assert imageData.height === 50;
+ assertArrayEquals(getRGBA(imageData.data, 4), [0, 0, 0, 0]);
+
+ var testColor = [0, 255, 255, 128];
+ setRGBA(imageData.data, 4, testColor);
+ assertArrayEquals(getRGBA(imageData.data, 4), testColor);
+
+ @assert throws TypeError ImageData(1, 1);
+ @assert throws TypeError new ImageData(10);
+ @assert throws INDEX_SIZE_ERR new ImageData(0, 10);
+ @assert throws INDEX_SIZE_ERR new ImageData(10, 0);
+ @assert throws INDEX_SIZE_ERR new ImageData('width', 'height');
+ @assert throws INDEX_SIZE_ERR new ImageData(1 << 31, 1 << 31);
+ @assert throws TypeError new ImageData(new Uint8ClampedArray(0));
+ @assert throws INDEX_SIZE_ERR new ImageData(new Uint8Array(100), 25);
+ @assert throws INVALID_STATE_ERR new ImageData(new Uint8ClampedArray(27), 2);
+ @assert throws INDEX_SIZE_ERR new ImageData(new Uint8ClampedArray(28), 7, 0);
+ @assert throws INDEX_SIZE_ERR new ImageData(new Uint8ClampedArray(104), 14);
+ @assert throws INDEX_SIZE_ERR new ImageData(new Uint8ClampedArray([12, 34, 168, 65328]), 1, 151);
+ @assert throws TypeError new ImageData(self, 4, 4);
+ @assert throws TypeError new ImageData(null, 4, 4);
+ @assert throws INDEX_SIZE_ERR new ImageData(imageData.data, 0);
+ @assert throws INDEX_SIZE_ERR new ImageData(imageData.data, 13);
+ @assert throws INDEX_SIZE_ERR new ImageData(imageData.data, 1 << 31);
+ @assert throws INDEX_SIZE_ERR new ImageData(imageData.data, 'biggish');
+ @assert throws INDEX_SIZE_ERR new ImageData(imageData.data, 1 << 24, 1 << 31);
+ @assert new ImageData(new Uint8ClampedArray(28), 7).height === 1;
+
+ imageDataFromData = new ImageData(imageData.data, 100);
+ @assert imageDataFromData.width === 100;
+ @assert imageDataFromData.height === 50;
+ @assert imageDataFromData.data === imageData.data;
+ assertArrayEquals(getRGBA(imageDataFromData.data, 10), getRGBA(imageData.data, 10));
+ setRGBA(imageData.data, 10, testColor);
+ assertArrayEquals(getRGBA(imageDataFromData.data, 10), getRGBA(imageData.data, 10));
+
+ var data = new Uint8ClampedArray(400);
+ data[22] = 129;
+ imageDataFromData = new ImageData(data, 20, 5);
+ @assert imageDataFromData.width === 20;
+ @assert imageDataFromData.height === 5;
+ @assert imageDataFromData.data === data;
+ assertArrayEquals(getRGBA(imageDataFromData.data, 2), getRGBA(data, 2));
+ setRGBA(imageDataFromData.data, 2, testColor);
+ assertArrayEquals(getRGBA(imageDataFromData.data, 2), getRGBA(data, 2));
+
+ if (window.SharedArrayBuffer) {
+ @assert throws TypeError new ImageData(new Uint16Array(new SharedArrayBuffer(32)), 4, 2);
+ }
+
+- name: 2d.imageData.object.ctor.array
+ desc: ImageData has a usable constructor
+ canvasType: ['HTMLCanvas']
+ code: |
+ @assert window.ImageData !== undefined;
+
+ var array = new Uint8ClampedArray(8);
+ var imgdata = new window.ImageData(array, 1, 2);
+ @assert imgdata.width === 1;
+ @assert imgdata.height === 2;
+ @assert imgdata.data === array;
+
+- name: 2d.imageData.object.ctor.array.bounds
+ desc: ImageData has a usable constructor
+ canvasType: ['HTMLCanvas']
+ code: |
+ @assert window.ImageData !== undefined;
+
+ @assert throws INVALID_STATE_ERR new ImageData(new Uint8ClampedArray(0), 1);
+ @assert throws INVALID_STATE_ERR new ImageData(new Uint8ClampedArray(3), 1);
+ @assert throws INDEX_SIZE_ERR new ImageData(new Uint8ClampedArray(4), 0);
+ @assert throws INDEX_SIZE_ERR new ImageData(new Uint8ClampedArray(4), 1, 2);
+ @assert throws TypeError new ImageData(new Uint8Array(8), 1, 2);
+ @assert throws TypeError new ImageData(new Int8Array(8), 1, 2);
+
+- name: 2d.imageData.object.set
+ desc: ImageData.data can be modified
+ code: |
+ var imgdata = ctx.getImageData(0, 0, 10, 10);
+ imgdata.data[0] = 100;
+ @assert imgdata.data[0] === 100;
+ imgdata.data[0] = 200;
+ @assert imgdata.data[0] === 200;
+
+- name: 2d.imageData.object.undefined
+ desc: ImageData.data converts undefined to 0
+ webidl:
+ - es-octet
+ code: |
+ var imgdata = ctx.getImageData(0, 0, 10, 10);
+ imgdata.data[0] = 100;
+ imgdata.data[0] = undefined;
+ @assert imgdata.data[0] === 0;
+
+- name: 2d.imageData.object.nan
+ desc: ImageData.data converts NaN to 0
+ webidl:
+ - es-octet
+ code: |
+ var imgdata = ctx.getImageData(0, 0, 10, 10);
+ imgdata.data[0] = 100;
+ imgdata.data[0] = NaN;
+ @assert imgdata.data[0] === 0;
+ imgdata.data[0] = 100;
+ imgdata.data[0] = "cheese";
+ @assert imgdata.data[0] === 0;
+
+- name: 2d.imageData.object.string
+ desc: ImageData.data converts strings to numbers with ToNumber
+ webidl:
+ - es-octet
+ code: |
+ var imgdata = ctx.getImageData(0, 0, 10, 10);
+ imgdata.data[0] = 100;
+ imgdata.data[0] = "110";
+ @assert imgdata.data[0] === 110;
+ imgdata.data[0] = 100;
+ imgdata.data[0] = "0x78";
+ @assert imgdata.data[0] === 120;
+ imgdata.data[0] = 100;
+ imgdata.data[0] = " +130e0 ";
+ @assert imgdata.data[0] === 130;
+
+- name: 2d.imageData.object.clamp
+ desc: ImageData.data clamps numbers to [0, 255]
+ webidl:
+ - es-octet
+ code: |
+ var imgdata = ctx.getImageData(0, 0, 10, 10);
+
+ imgdata.data[0] = 100;
+ imgdata.data[0] = 300;
+ @assert imgdata.data[0] === 255;
+ imgdata.data[0] = 100;
+ imgdata.data[0] = -100;
+ @assert imgdata.data[0] === 0;
+
+ imgdata.data[0] = 100;
+ imgdata.data[0] = 200+Math.pow(2, 32);
+ @assert imgdata.data[0] === 255;
+ imgdata.data[0] = 100;
+ imgdata.data[0] = -200-Math.pow(2, 32);
+ @assert imgdata.data[0] === 0;
+
+ imgdata.data[0] = 100;
+ imgdata.data[0] = Math.pow(10, 39);
+ @assert imgdata.data[0] === 255;
+ imgdata.data[0] = 100;
+ imgdata.data[0] = -Math.pow(10, 39);
+ @assert imgdata.data[0] === 0;
+
+ imgdata.data[0] = 100;
+ imgdata.data[0] = -Infinity;
+ @assert imgdata.data[0] === 0;
+ imgdata.data[0] = 100;
+ imgdata.data[0] = Infinity;
+ @assert imgdata.data[0] === 255;
+
+- name: 2d.imageData.object.round
+ desc: ImageData.data rounds numbers with round-to-zero
+ webidl:
+ - es-octet
+ code: |
+ var imgdata = ctx.getImageData(0, 0, 10, 10);
+ imgdata.data[0] = 0.499;
+ @assert imgdata.data[0] === 0;
+ imgdata.data[0] = 0.5;
+ @assert imgdata.data[0] === 0;
+ imgdata.data[0] = 0.501;
+ @assert imgdata.data[0] === 1;
+ imgdata.data[0] = 1.499;
+ @assert imgdata.data[0] === 1;
+ imgdata.data[0] = 1.5;
+ @assert imgdata.data[0] === 2;
+ imgdata.data[0] = 1.501;
+ @assert imgdata.data[0] === 2;
+ imgdata.data[0] = 2.5;
+ @assert imgdata.data[0] === 2;
+ imgdata.data[0] = 3.5;
+ @assert imgdata.data[0] === 4;
+ imgdata.data[0] = 252.5;
+ @assert imgdata.data[0] === 252;
+ imgdata.data[0] = 253.5;
+ @assert imgdata.data[0] === 254;
+ imgdata.data[0] = 254.5;
+ @assert imgdata.data[0] === 254;
+ imgdata.data[0] = 256.5;
+ @assert imgdata.data[0] === 255;
+ imgdata.data[0] = -0.5;
+ @assert imgdata.data[0] === 0;
+ imgdata.data[0] = -1.5;
+ @assert imgdata.data[0] === 0;
+
+
+
+- name: 2d.imageData.put.null
+ desc: putImageData() with null imagedata throws TypeError
+ code: |
+ @assert throws TypeError ctx.putImageData(null, 0, 0);
+
+- name: 2d.imageData.put.nonfinite
+ desc: putImageData() throws TypeError if arguments are not finite
+ notes: *bindings
+ code: |
+ var imgdata = ctx.getImageData(0, 0, 10, 10);
+ @nonfinite @assert throws TypeError ctx.putImageData(<imgdata>, <10 Infinity -Infinity NaN>, <10 Infinity -Infinity NaN>);
+ @nonfinite @assert throws TypeError ctx.putImageData(<imgdata>, <10 Infinity -Infinity NaN>, <10 Infinity -Infinity NaN>, <10 Infinity -Infinity NaN>, <10 Infinity -Infinity NaN>, <10 Infinity -Infinity NaN>, <10 Infinity -Infinity NaN>);
+
+- name: 2d.imageData.put.basic
+ desc: putImageData() puts image data from getImageData() onto the canvas
+ code: |
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 100, 50)
+ var imgdata = ctx.getImageData(0, 0, 100, 50);
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50)
+ ctx.putImageData(imgdata, 0, 0);
+ @assert pixel 50,25 ==~ 0,255,0,255;
+ expected: green
+
+- name: 2d.imageData.put.created
+ desc: putImageData() puts image data from createImageData() onto the canvas
+ code: |
+ var imgdata = ctx.createImageData(100, 50);
+ for (var i = 0; i < imgdata.data.length; i += 4) {
+ imgdata.data[i] = 0;
+ imgdata.data[i+1] = 255;
+ imgdata.data[i+2] = 0;
+ imgdata.data[i+3] = 255;
+ }
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50)
+ ctx.putImageData(imgdata, 0, 0);
+ @assert pixel 50,25 ==~ 0,255,0,255;
+ expected: green
+
+- name: 2d.imageData.put.wrongtype
+ desc: putImageData() does not accept non-ImageData objects
+ code: |
+ var imgdata = { width: 1, height: 1, data: [255, 0, 0, 255] };
+ @assert throws TypeError ctx.putImageData(imgdata, 0, 0);
+ @assert throws TypeError ctx.putImageData("cheese", 0, 0);
+ @assert throws TypeError ctx.putImageData(42, 0, 0);
+ expected: green
+
+- name: 2d.imageData.put.cross
+ desc: putImageData() accepts image data got from a different canvas
+ canvasType: ['HTMLCanvas']
+ code: |
+ var canvas2 = document.createElement('canvas');
+ var ctx2 = canvas2.getContext('2d');
+ ctx2.fillStyle = '#0f0';
+ ctx2.fillRect(0, 0, 100, 50)
+ var imgdata = ctx2.getImageData(0, 0, 100, 50);
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50)
+ ctx.putImageData(imgdata, 0, 0);
+ @assert pixel 50,25 ==~ 0,255,0,255;
+ expected: green
+
+- name: 2d.imageData.put.cross
+ desc: putImageData() accepts image data got from a different canvas
+ canvasType: ['OffscreenCanvas', 'Worker']
+ code: |
+ var offscreenCanvas2 = new OffscreenCanvas(100, 50);
+ var ctx2 = offscreenCanvas2.getContext('2d');
+ ctx2.fillStyle = '#0f0';
+ ctx2.fillRect(0, 0, 100, 50)
+ var imgdata = ctx2.getImageData(0, 0, 100, 50);
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50)
+ ctx.putImageData(imgdata, 0, 0);
+ @assert pixel 50,25 ==~ 0,255,0,255;
+ expected: green
+
+- name: 2d.imageData.put.alpha
+ desc: putImageData() puts non-solid image data correctly
+ code: |
+ ctx.fillStyle = 'rgba(0, 255, 0, 0.25)';
+ ctx.fillRect(0, 0, 100, 50)
+ var imgdata = ctx.getImageData(0, 0, 100, 50);
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50)
+ ctx.putImageData(imgdata, 0, 0);
+ @assert pixel 50,25 ==~ 0,255,0,64;
+ expected: |
+ size 100 50
+ cr.set_source_rgba(0, 1, 0, 0.25)
+ cr.rectangle(0, 0, 100, 50)
+ cr.fill()
+
+- name: 2d.imageData.put.modified
+ desc: putImageData() puts modified image data correctly
+ code: |
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 100, 50)
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(45, 20, 10, 10)
+ var imgdata = ctx.getImageData(45, 20, 10, 10);
+ for (var i = 0, len = imgdata.width*imgdata.height*4; i < len; i += 4)
+ {
+ imgdata.data[i] = 0;
+ imgdata.data[i+1] = 255;
+ }
+ ctx.putImageData(imgdata, 45, 20);
+ @assert pixel 50,25 ==~ 0,255,0,255;
+ expected: green
+
+- name: 2d.imageData.put.dirty.zero
+ desc: putImageData() with zero-sized dirty rectangle puts nothing
+ code: |
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50)
+ var imgdata = ctx.getImageData(0, 0, 100, 50);
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 100, 50)
+ ctx.putImageData(imgdata, 0, 0, 0, 0, 0, 0);
+ @assert pixel 50,25 ==~ 0,255,0,255;
+ expected: green
+
+- name: 2d.imageData.put.dirty.rect1
+ desc: putImageData() only modifies areas inside the dirty rectangle, using width
+ and height
+ code: |
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50)
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 20, 20)
+
+ var imgdata = ctx.getImageData(0, 0, 100, 50);
+
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 100, 50)
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(40, 20, 20, 20)
+ ctx.putImageData(imgdata, 40, 20, 0, 0, 20, 20);
+
+ @assert pixel 50,25 ==~ 0,255,0,255;
+ @assert pixel 35,25 ==~ 0,255,0,255;
+ @assert pixel 65,25 ==~ 0,255,0,255;
+ @assert pixel 50,15 ==~ 0,255,0,255;
+ @assert pixel 50,45 ==~ 0,255,0,255;
+ expected: green
+
+- name: 2d.imageData.put.dirty.rect2
+ desc: putImageData() only modifies areas inside the dirty rectangle, using x and
+ y
+ code: |
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50)
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(60, 30, 20, 20)
+
+ var imgdata = ctx.getImageData(0, 0, 100, 50);
+
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 100, 50)
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(40, 20, 20, 20)
+ ctx.putImageData(imgdata, -20, -10, 60, 30, 20, 20);
+
+ @assert pixel 50,25 ==~ 0,255,0,255;
+ @assert pixel 35,25 ==~ 0,255,0,255;
+ @assert pixel 65,25 ==~ 0,255,0,255;
+ @assert pixel 50,15 ==~ 0,255,0,255;
+ @assert pixel 50,45 ==~ 0,255,0,255;
+ expected: green
+
+- name: 2d.imageData.put.dirty.negative
+ desc: putImageData() handles negative-sized dirty rectangles correctly
+ code: |
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50)
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 20, 20)
+
+ var imgdata = ctx.getImageData(0, 0, 100, 50);
+
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 100, 50)
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(40, 20, 20, 20)
+ ctx.putImageData(imgdata, 40, 20, 20, 20, -20, -20);
+
+ @assert pixel 50,25 ==~ 0,255,0,255;
+ @assert pixel 35,25 ==~ 0,255,0,255;
+ @assert pixel 65,25 ==~ 0,255,0,255;
+ @assert pixel 50,15 ==~ 0,255,0,255;
+ @assert pixel 50,45 ==~ 0,255,0,255;
+ expected: green
+
+- name: 2d.imageData.put.dirty.outside
+ desc: putImageData() handles dirty rectangles outside the canvas correctly
+ code: |
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50)
+
+ var imgdata = ctx.getImageData(0, 0, 100, 50);
+
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 100, 50)
+
+ ctx.putImageData(imgdata, 100, 20, 20, 20, -20, -20);
+ ctx.putImageData(imgdata, 200, 200, 0, 0, 100, 50);
+ ctx.putImageData(imgdata, 40, 20, -30, -20, 30, 20);
+ ctx.putImageData(imgdata, -30, 20, 0, 0, 30, 20);
+
+ @assert pixel 50,25 ==~ 0,255,0,255;
+ @assert pixel 98,15 ==~ 0,255,0,255;
+ @assert pixel 98,25 ==~ 0,255,0,255;
+ @assert pixel 98,45 ==~ 0,255,0,255;
+ @assert pixel 1,5 ==~ 0,255,0,255;
+ @assert pixel 1,25 ==~ 0,255,0,255;
+ @assert pixel 1,45 ==~ 0,255,0,255;
+ expected: green
+
+- name: 2d.imageData.put.unchanged
+ desc: putImageData(getImageData(...), ...) has no effect
+ code: |
+ var i = 0;
+ for (var y = 0; y < 16; ++y) {
+ for (var x = 0; x < 16; ++x, ++i) {
+ ctx.fillStyle = 'rgba(' + i + ',' + (Math.floor(i*1.5) % 256) + ',' + (Math.floor(i*23.3) % 256) + ',' + (i/256) + ')';
+ ctx.fillRect(x, y, 1, 1);
+ }
+ }
+ var imgdata1 = ctx.getImageData(0.1, 0.2, 15.8, 15.9);
+ var olddata = [];
+ for (var i = 0; i < imgdata1.data.length; ++i)
+ olddata[i] = imgdata1.data[i];
+
+ ctx.putImageData(imgdata1, 0.1, 0.2);
+
+ var imgdata2 = ctx.getImageData(0.1, 0.2, 15.8, 15.9);
+ for (var i = 0; i < imgdata2.data.length; ++i) {
+ @assert olddata[i] === imgdata2.data[i];
+ }
+
+- name: 2d.imageData.put.unaffected
+ desc: putImageData() is not affected by context state
+ code: |
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 100, 50)
+ var imgdata = ctx.getImageData(0, 0, 100, 50);
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50)
+ ctx.globalAlpha = 0.1;
+ ctx.globalCompositeOperation = 'destination-atop';
+ ctx.shadowColor = '#f00';
+ ctx.shadowBlur = 1;
+ ctx.translate(100, 50);
+ ctx.scale(0.1, 0.1);
+ ctx.putImageData(imgdata, 0, 0);
+ @assert pixel 50,25 ==~ 0,255,0,255;
+ expected: green
+
+- name: 2d.imageData.put.clip
+ desc: putImageData() is not affected by clipping regions
+ code: |
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 100, 50)
+ var imgdata = ctx.getImageData(0, 0, 100, 50);
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50)
+ ctx.beginPath();
+ ctx.rect(0, 0, 50, 50);
+ ctx.clip();
+ ctx.putImageData(imgdata, 0, 0);
+ @assert pixel 25,25 ==~ 0,255,0,255;
+ @assert pixel 75,25 ==~ 0,255,0,255;
+ expected: green
+
+- name: 2d.imageData.put.path
+ desc: putImageData() does not affect the current path
+ code: |
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50)
+ ctx.rect(0, 0, 100, 50);
+ var imgdata = ctx.getImageData(0, 0, 100, 50);
+ ctx.putImageData(imgdata, 0, 0);
+ ctx.fillStyle = '#0f0';
+ ctx.fill();
+ @assert pixel 50,25 ==~ 0,255,0,255;
+ expected: green