1- name: 2d.imageData.create2.basic
2  desc: createImageData(sw, sh) exists and returns something
3  testing:
4  - 2d.imageData.create2.object
5  code: |
6    @assert ctx.createImageData(1, 1) !== null;
7
8- name: 2d.imageData.create1.basic
9  desc: createImageData(imgdata) exists and returns something
10  testing:
11  - 2d.imageData.create1.object
12  code: |
13    @assert ctx.createImageData(ctx.createImageData(1, 1)) !== null;
14
15- name: 2d.imageData.create2.type
16  desc: createImageData(sw, sh) returns an ImageData object containing a Uint8ClampedArray
17    object
18  testing:
19  - 2d.imageData.create2.object
20  code: |
21    @assert window.ImageData !== undefined;
22    @assert window.Uint8ClampedArray !== undefined;
23    window.ImageData.prototype.thisImplementsImageData = true;
24    window.Uint8ClampedArray.prototype.thisImplementsUint8ClampedArray = true;
25    var imgdata = ctx.createImageData(1, 1);
26    @assert imgdata.thisImplementsImageData;
27    @assert imgdata.data.thisImplementsUint8ClampedArray;
28
29- name: 2d.imageData.create1.type
30  desc: createImageData(imgdata) returns an ImageData object containing a Uint8ClampedArray
31    object
32  testing:
33  - 2d.imageData.create1.object
34  code: |
35    @assert window.ImageData !== undefined;
36    @assert window.Uint8ClampedArray !== undefined;
37    window.ImageData.prototype.thisImplementsImageData = true;
38    window.Uint8ClampedArray.prototype.thisImplementsUint8ClampedArray = true;
39    var imgdata = ctx.createImageData(ctx.createImageData(1, 1));
40    @assert imgdata.thisImplementsImageData;
41    @assert imgdata.data.thisImplementsUint8ClampedArray;
42
43- name: 2d.imageData.create2.this
44  desc: createImageData(sw, sh) should throw when called with the wrong |this|
45  notes: &bindings Defined in "Web IDL" (draft)
46  testing:
47  - 2d.imageData.create2.object
48  code: |
49    @assert throws TypeError CanvasRenderingContext2D.prototype.createImageData.call(null, 1, 1); @moz-todo
50    @assert throws TypeError CanvasRenderingContext2D.prototype.createImageData.call(undefined, 1, 1); @moz-todo
51    @assert throws TypeError CanvasRenderingContext2D.prototype.createImageData.call({}, 1, 1); @moz-todo
52
53- name: 2d.imageData.create1.this
54  desc: createImageData(imgdata) should throw when called with the wrong |this|
55  notes: *bindings
56  testing:
57  - 2d.imageData.create2.object
58  code: |
59    var imgdata = ctx.createImageData(1, 1);
60    @assert throws TypeError CanvasRenderingContext2D.prototype.createImageData.call(null, imgdata); @moz-todo
61    @assert throws TypeError CanvasRenderingContext2D.prototype.createImageData.call(undefined, imgdata); @moz-todo
62    @assert throws TypeError CanvasRenderingContext2D.prototype.createImageData.call({}, imgdata); @moz-todo
63
64- name: 2d.imageData.create2.initial
65  desc: createImageData(sw, sh) returns transparent black data of the right size
66  testing:
67  - 2d.imageData.create2.size
68  - 2d.imageData.create.initial
69  - 2d.imageData.initial
70  code: |
71    var imgdata = ctx.createImageData(10, 20);
72    @assert imgdata.data.length === imgdata.width*imgdata.height*4;
73    @assert imgdata.width < imgdata.height;
74    @assert imgdata.width > 0;
75    var isTransparentBlack = true;
76    for (var i = 0; i < imgdata.data.length; ++i)
77        if (imgdata.data[i] !== 0)
78            isTransparentBlack = false;
79    @assert isTransparentBlack;
80
81- name: 2d.imageData.create1.initial
82  desc: createImageData(imgdata) returns transparent black data of the right size
83  testing:
84  - 2d.imageData.create1.size
85  - 2d.imageData.create.initial
86  - 2d.imageData.initial
87  code: |
88    ctx.fillStyle = '#0f0';
89    ctx.fillRect(0, 0, 100, 50);
90    var imgdata1 = ctx.getImageData(0, 0, 10, 20);
91    var imgdata2 = ctx.createImageData(imgdata1);
92    @assert imgdata2.data.length === imgdata1.data.length;
93    @assert imgdata2.width === imgdata1.width;
94    @assert imgdata2.height === imgdata1.height;
95    var isTransparentBlack = true;
96    for (var i = 0; i < imgdata2.data.length; ++i)
97        if (imgdata2.data[i] !== 0)
98            isTransparentBlack = false;
99    @assert isTransparentBlack;
100
101- name: 2d.imageData.create2.large
102  desc: createImageData(sw, sh) works for sizes much larger than the canvas
103  testing:
104  - 2d.imageData.create2.size
105  code: |
106    var imgdata = ctx.createImageData(1000, 2000);
107    @assert imgdata.data.length === imgdata.width*imgdata.height*4;
108    @assert imgdata.width < imgdata.height;
109    @assert imgdata.width > 0;
110    var isTransparentBlack = true;
111    for (var i = 0; i < imgdata.data.length; i += 7813) // check ~1024 points (assuming normal scaling)
112        if (imgdata.data[i] !== 0)
113            isTransparentBlack = false;
114    @assert isTransparentBlack;
115
116- name: 2d.imageData.create2.negative
117  desc: createImageData(sw, sh) takes the absolute magnitude of the size arguments
118  testing:
119  - 2d.imageData.create2.size
120  code: |
121    var imgdata1 = ctx.createImageData(10, 20);
122    var imgdata2 = ctx.createImageData(-10, 20);
123    var imgdata3 = ctx.createImageData(10, -20);
124    var imgdata4 = ctx.createImageData(-10, -20);
125    @assert imgdata1.data.length === imgdata2.data.length;
126    @assert imgdata2.data.length === imgdata3.data.length;
127    @assert imgdata3.data.length === imgdata4.data.length;
128
129- name: 2d.imageData.create2.zero
130  desc: createImageData(sw, sh) throws INDEX_SIZE_ERR if size is zero
131  testing:
132  - 2d.imageData.getcreate.zero
133  code: |
134    @assert throws INDEX_SIZE_ERR ctx.createImageData(10, 0);
135    @assert throws INDEX_SIZE_ERR ctx.createImageData(0, 10);
136    @assert throws INDEX_SIZE_ERR ctx.createImageData(0, 0);
137    @assert throws INDEX_SIZE_ERR ctx.createImageData(0.99, 10);
138    @assert throws INDEX_SIZE_ERR ctx.createImageData(10, 0.1);
139
140- name: 2d.imageData.create2.nonfinite
141  desc: createImageData() throws TypeError if arguments are not finite
142  notes: *bindings
143  testing:
144  - 2d.imageData.getcreate.nonfinite
145  code: |
146    @nonfinite @assert throws TypeError ctx.createImageData(<10 Infinity -Infinity NaN>, <10 Infinity -Infinity NaN>);
147    var posinfobj = { valueOf: function() { return Infinity; } },
148        neginfobj = { valueOf: function() { return -Infinity; } },
149        nanobj = { valueOf: function() { return -Infinity; } };
150    @nonfinite @assert throws TypeError ctx.createImageData(<10 posinfobj neginfobj nanobj>, <10 posinfobj neginfobj nanobj>);
151
152- name: 2d.imageData.create1.zero
153  desc: createImageData(null) throws TypeError
154  testing:
155  - 2d.imageData.create.null
156  code: |
157    @assert throws TypeError ctx.createImageData(null);
158
159- name: 2d.imageData.create2.double
160  desc: createImageData(w, h) double is converted to long
161  testing:
162  - 2d.imageData.create2.size
163  code: |
164    var imgdata1 = ctx.createImageData(10.01, 10.99);
165    var imgdata2 = ctx.createImageData(-10.01, -10.99);
166    @assert imgdata1.width === 10;
167    @assert imgdata1.height === 10;
168    @assert imgdata2.width === 10;
169    @assert imgdata2.height === 10;
170
171- name: 2d.imageData.create.and.resize
172  desc: Verify no crash when resizing an image bitmap to zero.
173  testing:
174  - 2d.imageData.resize
175  images:
176  - red.png
177  code: |
178    var image = new Image();
179    image.onload = t.step_func(function() {
180      var options = { resizeHeight: 0 };
181      var p1 = createImageBitmap(image, options);
182      p1.catch(function(error){});
183      t.done();
184    });
185    image.src = 'red.png';
186
187- name: 2d.imageData.get.basic
188  desc: getImageData() exists and returns something
189  testing:
190  - 2d.imageData.get.basic
191  code: |
192    @assert ctx.getImageData(0, 0, 100, 50) !== null;
193
194- name: 2d.imageData.get.type
195  desc: getImageData() returns an ImageData object containing a Uint8ClampedArray
196    object
197  testing:
198  - 2d.imageData.get.object
199  code: |
200    @assert window.ImageData !== undefined;
201    @assert window.Uint8ClampedArray !== undefined;
202    window.ImageData.prototype.thisImplementsImageData = true;
203    window.Uint8ClampedArray.prototype.thisImplementsUint8ClampedArray = true;
204    var imgdata = ctx.getImageData(0, 0, 1, 1);
205    @assert imgdata.thisImplementsImageData;
206    @assert imgdata.data.thisImplementsUint8ClampedArray;
207
208- name: 2d.imageData.get.zero
209  desc: getImageData() throws INDEX_SIZE_ERR if size is zero
210  testing:
211  - 2d.imageData.getcreate.zero
212  code: |
213    @assert throws INDEX_SIZE_ERR ctx.getImageData(1, 1, 10, 0);
214    @assert throws INDEX_SIZE_ERR ctx.getImageData(1, 1, 0, 10);
215    @assert throws INDEX_SIZE_ERR ctx.getImageData(1, 1, 0, 0);
216    @assert throws INDEX_SIZE_ERR ctx.getImageData(1, 1, 0.1, 10);
217    @assert throws INDEX_SIZE_ERR ctx.getImageData(1, 1, 10, 0.99);
218    @assert throws INDEX_SIZE_ERR ctx.getImageData(1, 1, -0.1, 10);
219    @assert throws INDEX_SIZE_ERR ctx.getImageData(1, 1, 10, -0.99);
220
221- name: 2d.imageData.get.nonfinite
222  desc: getImageData() throws TypeError if arguments are not finite
223  notes: *bindings
224  testing:
225  - 2d.imageData.getcreate.nonfinite
226  code: |
227    @nonfinite @assert throws TypeError ctx.getImageData(<10 Infinity -Infinity NaN>, <10 Infinity -Infinity NaN>, <10 Infinity -Infinity NaN>, <10 Infinity -Infinity NaN>);
228    var posinfobj = { valueOf: function() { return Infinity; } },
229        neginfobj = { valueOf: function() { return -Infinity; } },
230        nanobj = { valueOf: function() { return -Infinity; } };
231    @nonfinite @assert throws TypeError ctx.getImageData(<10 posinfobj neginfobj nanobj>, <10 posinfobj neginfobj nanobj>, <10 posinfobj neginfobj nanobj>, <10 posinfobj neginfobj nanobj>);
232
233- name: 2d.imageData.get.source.outside
234  desc: getImageData() returns transparent black outside the canvas
235  testing:
236  - 2d.imageData.get.basic
237  - 2d.imageData.get.outside
238  code: |
239    ctx.fillStyle = '#08f';
240    ctx.fillRect(0, 0, 100, 50);
241
242    var imgdata1 = ctx.getImageData(-10, 5, 1, 1);
243    @assert imgdata1.data[0] === 0;
244    @assert imgdata1.data[1] === 0;
245    @assert imgdata1.data[2] === 0;
246    @assert imgdata1.data[3] === 0;
247
248    var imgdata2 = ctx.getImageData(10, -5, 1, 1);
249    @assert imgdata2.data[0] === 0;
250    @assert imgdata2.data[1] === 0;
251    @assert imgdata2.data[2] === 0;
252    @assert imgdata2.data[3] === 0;
253
254    var imgdata3 = ctx.getImageData(200, 5, 1, 1);
255    @assert imgdata3.data[0] === 0;
256    @assert imgdata3.data[1] === 0;
257    @assert imgdata3.data[2] === 0;
258    @assert imgdata3.data[3] === 0;
259
260    var imgdata4 = ctx.getImageData(10, 60, 1, 1);
261    @assert imgdata4.data[0] === 0;
262    @assert imgdata4.data[1] === 0;
263    @assert imgdata4.data[2] === 0;
264    @assert imgdata4.data[3] === 0;
265
266    var imgdata5 = ctx.getImageData(100, 10, 1, 1);
267    @assert imgdata5.data[0] === 0;
268    @assert imgdata5.data[1] === 0;
269    @assert imgdata5.data[2] === 0;
270    @assert imgdata5.data[3] === 0;
271
272    var imgdata6 = ctx.getImageData(0, 10, 1, 1);
273    @assert imgdata6.data[0] === 0;
274    @assert imgdata6.data[1] === 136;
275    @assert imgdata6.data[2] === 255;
276    @assert imgdata6.data[3] === 255;
277
278    var imgdata7 = ctx.getImageData(-10, 10, 20, 20);
279    @assert imgdata7.data[ 0*4+0] === 0;
280    @assert imgdata7.data[ 0*4+1] === 0;
281    @assert imgdata7.data[ 0*4+2] === 0;
282    @assert imgdata7.data[ 0*4+3] === 0;
283    @assert imgdata7.data[ 9*4+0] === 0;
284    @assert imgdata7.data[ 9*4+1] === 0;
285    @assert imgdata7.data[ 9*4+2] === 0;
286    @assert imgdata7.data[ 9*4+3] === 0;
287    @assert imgdata7.data[10*4+0] === 0;
288    @assert imgdata7.data[10*4+1] === 136;
289    @assert imgdata7.data[10*4+2] === 255;
290    @assert imgdata7.data[10*4+3] === 255;
291    @assert imgdata7.data[19*4+0] === 0;
292    @assert imgdata7.data[19*4+1] === 136;
293    @assert imgdata7.data[19*4+2] === 255;
294    @assert imgdata7.data[19*4+3] === 255;
295    @assert imgdata7.data[20*4+0] === 0;
296    @assert imgdata7.data[20*4+1] === 0;
297    @assert imgdata7.data[20*4+2] === 0;
298    @assert imgdata7.data[20*4+3] === 0;
299
300- name: 2d.imageData.get.source.negative
301  desc: getImageData() works with negative width and height, and returns top-to-bottom
302    left-to-right
303  testing:
304  - 2d.imageData.get.basic
305  - 2d.pixelarray.order
306  code: |
307    ctx.fillStyle = '#000';
308    ctx.fillRect(0, 0, 100, 50);
309    ctx.fillStyle = '#fff';
310    ctx.fillRect(20, 10, 60, 10);
311
312    var imgdata1 = ctx.getImageData(85, 25, -10, -10);
313    @assert imgdata1.data[0] === 255;
314    @assert imgdata1.data[1] === 255;
315    @assert imgdata1.data[2] === 255;
316    @assert imgdata1.data[3] === 255;
317    @assert imgdata1.data[imgdata1.data.length-4+0] === 0;
318    @assert imgdata1.data[imgdata1.data.length-4+1] === 0;
319    @assert imgdata1.data[imgdata1.data.length-4+2] === 0;
320    @assert imgdata1.data[imgdata1.data.length-4+3] === 255;
321
322    var imgdata2 = ctx.getImageData(0, 0, -1, -1);
323    @assert imgdata2.data[0] === 0;
324    @assert imgdata2.data[1] === 0;
325    @assert imgdata2.data[2] === 0;
326    @assert imgdata2.data[3] === 0;
327
328- name: 2d.imageData.get.source.size
329  desc: getImageData() returns bigger ImageData for bigger source rectangle
330  testing:
331  - 2d.imageData.get.basic
332  code: |
333    var imgdata1 = ctx.getImageData(0, 0, 10, 10);
334    var imgdata2 = ctx.getImageData(0, 0, 20, 20);
335    @assert imgdata2.width > imgdata1.width;
336    @assert imgdata2.height > imgdata1.height;
337
338- name: 2d.imageData.get.double
339  desc: createImageData(w, h) double is converted to long
340  testing:
341  - 2d.imageData.get.basic
342  code: |
343    var imgdata1 = ctx.getImageData(0, 0, 10.01, 10.99);
344    var imgdata2 = ctx.getImageData(0, 0, -10.01, -10.99);
345    @assert imgdata1.width === 10;
346    @assert imgdata1.height === 10;
347    @assert imgdata2.width === 10;
348    @assert imgdata2.height === 10;
349
350- name: 2d.imageData.get.nonpremul
351  desc: getImageData() returns non-premultiplied colours
352  testing:
353  - 2d.imageData.get.premul
354  code: |
355    ctx.fillStyle = 'rgba(255, 255, 255, 0.5)';
356    ctx.fillRect(0, 0, 100, 50);
357    var imgdata = ctx.getImageData(10, 10, 10, 10);
358    @assert imgdata.data[0] > 200;
359    @assert imgdata.data[1] > 200;
360    @assert imgdata.data[2] > 200;
361    @assert imgdata.data[3] > 100;
362    @assert imgdata.data[3] < 200;
363
364- name: 2d.imageData.get.range
365  desc: getImageData() returns values in the range [0, 255]
366  testing:
367  - 2d.pixelarray.range
368  - 2d.pixelarray.retrieve
369  code: |
370    ctx.fillStyle = '#000';
371    ctx.fillRect(0, 0, 100, 50);
372    ctx.fillStyle = '#fff';
373    ctx.fillRect(20, 10, 60, 10);
374    var imgdata1 = ctx.getImageData(10, 5, 1, 1);
375    @assert imgdata1.data[0] === 0;
376    var imgdata2 = ctx.getImageData(30, 15, 1, 1);
377    @assert imgdata2.data[0] === 255;
378
379- name: 2d.imageData.get.clamp
380  desc: getImageData() clamps colours to the range [0, 255]
381  testing:
382  - 2d.pixelarray.range
383  code: |
384    ctx.fillStyle = 'rgb(-100, -200, -300)';
385    ctx.fillRect(0, 0, 100, 50);
386    ctx.fillStyle = 'rgb(256, 300, 400)';
387    ctx.fillRect(20, 10, 60, 10);
388    var imgdata1 = ctx.getImageData(10, 5, 1, 1);
389    @assert imgdata1.data[0] === 0;
390    @assert imgdata1.data[1] === 0;
391    @assert imgdata1.data[2] === 0;
392    var imgdata2 = ctx.getImageData(30, 15, 1, 1);
393    @assert imgdata2.data[0] === 255;
394    @assert imgdata2.data[1] === 255;
395    @assert imgdata2.data[2] === 255;
396
397- name: 2d.imageData.get.length
398  desc: getImageData() returns a correctly-sized Uint8ClampedArray
399  testing:
400  - 2d.pixelarray.length
401  code: |
402    var imgdata = ctx.getImageData(0, 0, 10, 10);
403    @assert imgdata.data.length === imgdata.width*imgdata.height*4;
404
405- name: 2d.imageData.get.order.cols
406  desc: getImageData() returns leftmost columns first
407  testing:
408  - 2d.pixelarray.order
409  code: |
410    ctx.fillStyle = '#fff';
411    ctx.fillRect(0, 0, 100, 50);
412    ctx.fillStyle = '#000';
413    ctx.fillRect(0, 0, 2, 50);
414    var imgdata = ctx.getImageData(0, 0, 10, 10);
415    @assert imgdata.data[0] === 0;
416    @assert imgdata.data[Math.round(imgdata.width/2*4)] === 255;
417    @assert imgdata.data[Math.round((imgdata.height/2)*imgdata.width*4)] === 0;
418
419- name: 2d.imageData.get.order.rows
420  desc: getImageData() returns topmost rows first
421  testing:
422  - 2d.pixelarray.order
423  code: |
424    ctx.fillStyle = '#fff';
425    ctx.fillRect(0, 0, 100, 50);
426    ctx.fillStyle = '#000';
427    ctx.fillRect(0, 0, 100, 2);
428    var imgdata = ctx.getImageData(0, 0, 10, 10);
429    @assert imgdata.data[0] === 0;
430    @assert imgdata.data[Math.floor(imgdata.width/2*4)] === 0;
431    @assert imgdata.data[(imgdata.height/2)*imgdata.width*4] === 255;
432
433- name: 2d.imageData.get.order.rgb
434  desc: getImageData() returns R then G then B
435  testing:
436  - 2d.pixelarray.order
437  - 2d.pixelarray.indexes
438  code: |
439    ctx.fillStyle = '#48c';
440    ctx.fillRect(0, 0, 100, 50);
441    var imgdata = ctx.getImageData(0, 0, 10, 10);
442    @assert imgdata.data[0] === 0x44;
443    @assert imgdata.data[1] === 0x88;
444    @assert imgdata.data[2] === 0xCC;
445    @assert imgdata.data[3] === 255;
446    @assert imgdata.data[4] === 0x44;
447    @assert imgdata.data[5] === 0x88;
448    @assert imgdata.data[6] === 0xCC;
449    @assert imgdata.data[7] === 255;
450
451- name: 2d.imageData.get.order.alpha
452  desc: getImageData() returns A in the fourth component
453  testing:
454  - 2d.pixelarray.order
455  code: |
456    ctx.fillStyle = 'rgba(0, 0, 0, 0.5)';
457    ctx.fillRect(0, 0, 100, 50);
458    var imgdata = ctx.getImageData(0, 0, 10, 10);
459    @assert imgdata.data[3] < 200;
460    @assert imgdata.data[3] > 100;
461
462- name: 2d.imageData.get.unaffected
463  desc: getImageData() is not affected by context state
464  testing:
465  - 2d.imageData.unaffected
466  code: |
467    ctx.fillStyle = '#0f0';
468    ctx.fillRect(0, 0, 50, 50)
469    ctx.fillStyle = '#f00';
470    ctx.fillRect(50, 0, 50, 50)
471    ctx.save();
472    ctx.translate(50, 0);
473    ctx.globalAlpha = 0.1;
474    ctx.globalCompositeOperation = 'destination-atop';
475    ctx.shadowColor = '#f00';
476    ctx.rect(0, 0, 5, 5);
477    ctx.clip();
478    var imgdata = ctx.getImageData(0, 0, 50, 50);
479    ctx.restore();
480    ctx.putImageData(imgdata, 50, 0);
481    @assert pixel 25,25 ==~ 0,255,0,255;
482    @assert pixel 75,25 ==~ 0,255,0,255;
483  expected: green
484
485
486- name: 2d.imageData.get.large.crash
487  desc: Test that canvas crash when image data cannot be allocated.
488  testing:
489  - 2d.getImageData
490  code: |
491    @assert throws TypeError ctx.getImageData(10, 0xffffffff, 2147483647, 10);
492
493- name: 2d.imageData.get.rounding
494  desc: Test the handling of non-integer source coordinates in getImageData().
495  testing:
496  - 2d.getImageData
497  code: |
498    function testDimensions(sx, sy, sw, sh, width, height)
499    {
500        imageData = ctx.getImageData(sx, sy, sw, sh);
501        @assert imageData.width == width;
502        @assert imageData.height == height;
503    }
504
505    testDimensions(0, 0, 20, 10, 20, 10);
506
507    testDimensions(.1, .2, 20, 10, 20, 10);
508    testDimensions(.9, .8, 20, 10, 20, 10);
509
510    testDimensions(0, 0, 20.9, 10.9, 20, 10);
511    testDimensions(0, 0, 20.1, 10.1, 20, 10);
512
513    testDimensions(-1, -1, 20, 10, 20, 10);
514
515    testDimensions(-1.1, 0, 20, 10, 20, 10);
516    testDimensions(-1.9,  0, 20, 10, 20, 10);
517
518- name: 2d.imageData.get.invalid
519  desc: Verify getImageData() behavior in invalid cases.
520  testing:
521  - 2d.imageData.get.invalid
522  code: |
523    imageData = ctx.getImageData(0,0,2,2);
524    var testValues = [NaN, true, false, "\"garbage\"", "-1",
525                      "0", "1", "2", Infinity, -Infinity,
526                      -5, -0.5, 0, 0.5, 5,
527                      5.4, 255, 256, null, undefined];
528    var testResults = [0, 1, 0, 0, 0,
529                       0, 1, 2, 255, 0,
530                       0, 0, 0, 0, 5,
531                       5, 255, 255, 0, 0];
532    for (var i = 0; i < testValues.length; i++) {
533        imageData.data[0] = testValues[i];
534        @assert imageData.data[0] == testResults[i];
535    }
536    imageData.data['foo']='garbage';
537    @assert imageData.data['foo'] == 'garbage';
538    imageData.data[-1]='garbage';
539    @assert imageData.data[-1] == undefined;
540    imageData.data[17]='garbage';
541    @assert imageData.data[17] == undefined;
542
543- name: 2d.imageData.object.properties
544  desc: ImageData objects have the right properties
545  testing:
546  - 2d.imageData.type
547  code: |
548    var imgdata = ctx.getImageData(0, 0, 10, 10);
549    @assert typeof(imgdata.width) === 'number';
550    @assert typeof(imgdata.height) === 'number';
551    @assert typeof(imgdata.data) === 'object';
552
553- name: 2d.imageData.object.readonly
554  desc: ImageData objects properties are read-only
555  testing:
556  - 2d.imageData.type
557  code: |
558    var imgdata = ctx.getImageData(0, 0, 10, 10);
559    var w = imgdata.width;
560    var h = imgdata.height;
561    var d = imgdata.data;
562    imgdata.width = 123;
563    imgdata.height = 123;
564    imgdata.data = [100,100,100,100];
565    @assert imgdata.width === w;
566    @assert imgdata.height === h;
567    @assert imgdata.data === d;
568    @assert imgdata.data[0] === 0;
569    @assert imgdata.data[1] === 0;
570    @assert imgdata.data[2] === 0;
571    @assert imgdata.data[3] === 0;
572
573- name: 2d.imageData.object.ctor.size
574  desc: ImageData has a usable constructor
575  testing:
576  - 2d.imageData.type
577  code: |
578    @assert window.ImageData !== undefined;
579
580    var imgdata = new window.ImageData(2, 3);
581    @assert imgdata.width === 2;
582    @assert imgdata.height === 3;
583    @assert imgdata.data.length === 2 * 3 * 4;
584    for (var i = 0; i < imgdata.data.length; ++i) {
585      @assert imgdata.data[i] === 0;
586    }
587
588- name: 2d.imageData.object.ctor.basics
589  desc: Testing different type of ImageData constructor
590  testing:
591  - 2d.imageData.type
592  code: |
593    function setRGBA(imageData, i, rgba)
594    {
595        var s = i * 4;
596        imageData[s] = rgba[0];
597        imageData[s + 1] = rgba[1];
598        imageData[s + 2] = rgba[2];
599        imageData[s + 3] = rgba[3];
600    }
601
602    function getRGBA(imageData, i)
603    {
604        var result = [];
605        var s = i * 4;
606        for (var j = 0; j < 4; j++) {
607            result[j] = imageData[s + j];
608        }
609        return result;
610    }
611
612    function assertArrayEquals(actual, expected)
613    {
614        @assert typeof actual === "object";
615        @assert actual !== null;
616        @assert "length" in actual === true;
617        @assert actual.length === expected.length;
618        for (var i = 0; i < actual.length; i++) {
619            @assert actual.hasOwnProperty(i) === expected.hasOwnProperty(i);
620            @assert actual[i] === expected[i];
621        }
622    }
623
624    @assert ImageData !== undefined;
625    imageData = new ImageData(100, 50);
626
627    @assert imageData !== null;
628    @assert imageData.data !== null;
629    @assert imageData.width === 100;
630    @assert imageData.height === 50;
631    assertArrayEquals(getRGBA(imageData.data, 4), [0, 0, 0, 0]);
632
633    var testColor = [0, 255, 255, 128];
634    setRGBA(imageData.data, 4, testColor);
635    assertArrayEquals(getRGBA(imageData.data, 4), testColor);
636
637    @assert throws TypeError new ImageData(10);
638    @assert throws INDEX_SIZE_ERR new ImageData(0, 10);
639    @assert throws INDEX_SIZE_ERR new ImageData(10, 0);
640    @assert throws INDEX_SIZE_ERR new ImageData('width', 'height');
641    @assert throws INDEX_SIZE_ERR new ImageData(1 << 31, 1 << 31);
642    @assert throws TypeError new ImageData(new Uint8ClampedArray(0));
643    @assert throws INDEX_SIZE_ERR new ImageData(new Uint8Array(100), 25);
644    @assert throws INVALID_STATE_ERR new ImageData(new Uint8ClampedArray(27), 2);
645    @assert throws INDEX_SIZE_ERR new ImageData(new Uint8ClampedArray(28), 7, 0);
646    @assert throws INDEX_SIZE_ERR new ImageData(new Uint8ClampedArray(104), 14);
647    @assert throws INDEX_SIZE_ERR new ImageData(new Uint8ClampedArray([12, 34, 168, 65328]), 1, 151);
648    @assert throws TypeError new ImageData(self, 4, 4);
649    @assert throws TypeError new ImageData(null, 4, 4);
650    @assert throws INDEX_SIZE_ERR new ImageData(imageData.data, 0);
651    @assert throws INDEX_SIZE_ERR new ImageData(imageData.data, 13);
652    @assert throws INDEX_SIZE_ERR new ImageData(imageData.data, 1 << 31);
653    @assert throws INDEX_SIZE_ERR new ImageData(imageData.data, 'biggish');
654    @assert throws INDEX_SIZE_ERR new ImageData(imageData.data, 1 << 24, 1 << 31);
655    @assert new ImageData(new Uint8ClampedArray(28), 7).height === 1;
656
657    imageDataFromData = new ImageData(imageData.data, 100);
658    @assert imageDataFromData.width === 100;
659    @assert imageDataFromData.height === 50;
660    @assert imageDataFromData.data === imageData.data;
661    assertArrayEquals(getRGBA(imageDataFromData.data, 10), getRGBA(imageData.data, 10));
662    setRGBA(imageData.data, 10, testColor);
663    assertArrayEquals(getRGBA(imageDataFromData.data, 10), getRGBA(imageData.data, 10));
664
665    var data = new Uint8ClampedArray(400);
666    data[22] = 129;
667    imageDataFromData = new ImageData(data, 20, 5);
668    @assert imageDataFromData.width === 20;
669    @assert imageDataFromData.height === 5;
670    @assert imageDataFromData.data === data;
671    assertArrayEquals(getRGBA(imageDataFromData.data, 2), getRGBA(data, 2));
672    setRGBA(imageDataFromData.data, 2, testColor);
673    assertArrayEquals(getRGBA(imageDataFromData.data, 2), getRGBA(data, 2));
674
675    if (window.SharedArrayBuffer) {
676        @assert throws TypeError new ImageData(new Uint16Array(new SharedArrayBuffer(32)), 4, 2);
677    }
678
679- name: 2d.imageData.object.ctor.array
680  desc: ImageData has a usable constructor
681  testing:
682  - 2d.imageData.type
683  code: |
684    @assert window.ImageData !== undefined;
685
686    var array = new Uint8ClampedArray(8);
687    var imgdata = new window.ImageData(array, 1, 2);
688    @assert imgdata.width === 1;
689    @assert imgdata.height === 2;
690    @assert imgdata.data === array;
691
692- name: 2d.imageData.object.ctor.array.bounds
693  desc: ImageData has a usable constructor
694  testing:
695  - 2d.imageData.type
696  code: |
697    @assert window.ImageData !== undefined;
698
699    @assert throws INVALID_STATE_ERR new ImageData(new Uint8ClampedArray(0), 1);
700    @assert throws INVALID_STATE_ERR new ImageData(new Uint8ClampedArray(3), 1);
701    @assert throws INDEX_SIZE_ERR new ImageData(new Uint8ClampedArray(4), 0);
702    @assert throws INDEX_SIZE_ERR new ImageData(new Uint8ClampedArray(4), 1, 2);
703    @assert throws TypeError new ImageData(new Uint8Array(8), 1, 2);
704    @assert throws TypeError new ImageData(new Int8Array(8), 1, 2);
705
706- name: 2d.imageData.object.set
707  desc: ImageData.data can be modified
708  testing:
709  - 2d.pixelarray.modify
710  code: |
711    var imgdata = ctx.getImageData(0, 0, 10, 10);
712    imgdata.data[0] = 100;
713    @assert imgdata.data[0] === 100;
714    imgdata.data[0] = 200;
715    @assert imgdata.data[0] === 200;
716
717- name: 2d.imageData.object.undefined
718  desc: ImageData.data converts undefined to 0
719  testing:
720  - 2d.pixelarray.modify
721  webidl:
722  - es-octet
723  code: |
724    var imgdata = ctx.getImageData(0, 0, 10, 10);
725    imgdata.data[0] = 100;
726    imgdata.data[0] = undefined;
727    @assert imgdata.data[0] === 0;
728
729- name: 2d.imageData.object.nan
730  desc: ImageData.data converts NaN to 0
731  testing:
732  - 2d.pixelarray.modify
733  webidl:
734  - es-octet
735  code: |
736    var imgdata = ctx.getImageData(0, 0, 10, 10);
737    imgdata.data[0] = 100;
738    imgdata.data[0] = NaN;
739    @assert imgdata.data[0] === 0;
740    imgdata.data[0] = 100;
741    imgdata.data[0] = "cheese";
742    @assert imgdata.data[0] === 0;
743
744- name: 2d.imageData.object.string
745  desc: ImageData.data converts strings to numbers with ToNumber
746  testing:
747  - 2d.pixelarray.modify
748  webidl:
749  - es-octet
750  code: |
751    var imgdata = ctx.getImageData(0, 0, 10, 10);
752    imgdata.data[0] = 100;
753    imgdata.data[0] = "110";
754    @assert imgdata.data[0] === 110;
755    imgdata.data[0] = 100;
756    imgdata.data[0] = "0x78";
757    @assert imgdata.data[0] === 120;
758    imgdata.data[0] = 100;
759    imgdata.data[0] = " +130e0 ";
760    @assert imgdata.data[0] === 130;
761
762- name: 2d.imageData.object.clamp
763  desc: ImageData.data clamps numbers to [0, 255]
764  testing:
765  - 2d.pixelarray.modify
766  webidl:
767  - es-octet
768  code: |
769    var imgdata = ctx.getImageData(0, 0, 10, 10);
770
771    imgdata.data[0] = 100;
772    imgdata.data[0] = 300;
773    @assert imgdata.data[0] === 255;
774    imgdata.data[0] = 100;
775    imgdata.data[0] = -100;
776    @assert imgdata.data[0] === 0;
777
778    imgdata.data[0] = 100;
779    imgdata.data[0] = 200+Math.pow(2, 32);
780    @assert imgdata.data[0] === 255;
781    imgdata.data[0] = 100;
782    imgdata.data[0] = -200-Math.pow(2, 32);
783    @assert imgdata.data[0] === 0;
784
785    imgdata.data[0] = 100;
786    imgdata.data[0] = Math.pow(10, 39);
787    @assert imgdata.data[0] === 255;
788    imgdata.data[0] = 100;
789    imgdata.data[0] = -Math.pow(10, 39);
790    @assert imgdata.data[0] === 0;
791
792    imgdata.data[0] = 100;
793    imgdata.data[0] = -Infinity;
794    @assert imgdata.data[0] === 0;
795    imgdata.data[0] = 100;
796    imgdata.data[0] = Infinity;
797    @assert imgdata.data[0] === 255;
798
799- name: 2d.imageData.object.round
800  desc: ImageData.data rounds numbers with round-to-zero
801  testing:
802  - 2d.pixelarray.modify
803  webidl:
804  - es-octet
805  code: |
806    var imgdata = ctx.getImageData(0, 0, 10, 10);
807    imgdata.data[0] = 0.499;
808    @assert imgdata.data[0] === 0;
809    imgdata.data[0] = 0.5;
810    @assert imgdata.data[0] === 0;
811    imgdata.data[0] = 0.501;
812    @assert imgdata.data[0] === 1;
813    imgdata.data[0] = 1.499;
814    @assert imgdata.data[0] === 1;
815    imgdata.data[0] = 1.5;
816    @assert imgdata.data[0] === 2;
817    imgdata.data[0] = 1.501;
818    @assert imgdata.data[0] === 2;
819    imgdata.data[0] = 2.5;
820    @assert imgdata.data[0] === 2;
821    imgdata.data[0] = 3.5;
822    @assert imgdata.data[0] === 4;
823    imgdata.data[0] = 252.5;
824    @assert imgdata.data[0] === 252;
825    imgdata.data[0] = 253.5;
826    @assert imgdata.data[0] === 254;
827    imgdata.data[0] = 254.5;
828    @assert imgdata.data[0] === 254;
829    imgdata.data[0] = 256.5;
830    @assert imgdata.data[0] === 255;
831    imgdata.data[0] = -0.5;
832    @assert imgdata.data[0] === 0;
833    imgdata.data[0] = -1.5;
834    @assert imgdata.data[0] === 0;
835
836
837
838- name: 2d.imageData.put.null
839  desc: putImageData() with null imagedata throws TypeError
840  testing:
841  - 2d.imageData.put.wrongtype
842  code: |
843    @assert throws TypeError ctx.putImageData(null, 0, 0);
844
845- name: 2d.imageData.put.nonfinite
846  desc: putImageData() throws TypeError if arguments are not finite
847  notes: *bindings
848  testing:
849  - 2d.imageData.put.nonfinite
850  code: |
851    var imgdata = ctx.getImageData(0, 0, 10, 10);
852    @nonfinite @assert throws TypeError ctx.putImageData(<imgdata>, <10 Infinity -Infinity NaN>, <10 Infinity -Infinity NaN>);
853    @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>);
854
855- name: 2d.imageData.put.basic
856  desc: putImageData() puts image data from getImageData() onto the canvas
857  testing:
858  - 2d.imageData.put.normal
859  - 2d.imageData.put.3arg
860  code: |
861    ctx.fillStyle = '#0f0';
862    ctx.fillRect(0, 0, 100, 50)
863    var imgdata = ctx.getImageData(0, 0, 100, 50);
864    ctx.fillStyle = '#f00';
865    ctx.fillRect(0, 0, 100, 50)
866    ctx.putImageData(imgdata, 0, 0);
867    @assert pixel 50,25 ==~ 0,255,0,255;
868  expected: green
869
870- name: 2d.imageData.put.created
871  desc: putImageData() puts image data from createImageData() onto the canvas
872  testing:
873  - 2d.imageData.put.normal
874  code: |
875    var imgdata = ctx.createImageData(100, 50);
876    for (var i = 0; i < imgdata.data.length; i += 4) {
877        imgdata.data[i] = 0;
878        imgdata.data[i+1] = 255;
879        imgdata.data[i+2] = 0;
880        imgdata.data[i+3] = 255;
881    }
882    ctx.fillStyle = '#f00';
883    ctx.fillRect(0, 0, 100, 50)
884    ctx.putImageData(imgdata, 0, 0);
885    @assert pixel 50,25 ==~ 0,255,0,255;
886  expected: green
887
888- name: 2d.imageData.put.wrongtype
889  desc: putImageData() does not accept non-ImageData objects
890  testing:
891  - 2d.imageData.put.wrongtype
892  code: |
893    var imgdata = { width: 1, height: 1, data: [255, 0, 0, 255] };
894    @assert throws TypeError ctx.putImageData(imgdata, 0, 0);
895    @assert throws TypeError ctx.putImageData("cheese", 0, 0);
896    @assert throws TypeError ctx.putImageData(42, 0, 0);
897  expected: green
898
899- name: 2d.imageData.put.cross
900  desc: putImageData() accepts image data got from a different canvas
901  testing:
902  - 2d.imageData.put.normal
903  code: |
904    var canvas2 = document.createElement('canvas');
905    var ctx2 = canvas2.getContext('2d');
906    ctx2.fillStyle = '#0f0';
907    ctx2.fillRect(0, 0, 100, 50)
908    var imgdata = ctx2.getImageData(0, 0, 100, 50);
909    ctx.fillStyle = '#f00';
910    ctx.fillRect(0, 0, 100, 50)
911    ctx.putImageData(imgdata, 0, 0);
912    @assert pixel 50,25 ==~ 0,255,0,255;
913  expected: green
914
915- name: 2d.imageData.put.alpha
916  desc: putImageData() puts non-solid image data correctly
917  testing:
918  - 2d.imageData.put.normal
919  code: |
920    ctx.fillStyle = 'rgba(0, 255, 0, 0.25)';
921    ctx.fillRect(0, 0, 100, 50)
922    var imgdata = ctx.getImageData(0, 0, 100, 50);
923    ctx.fillStyle = '#f00';
924    ctx.fillRect(0, 0, 100, 50)
925    ctx.putImageData(imgdata, 0, 0);
926    @assert pixel 50,25 ==~ 0,255,0,64;
927  expected: |
928    size 100 50
929    cr.set_source_rgba(0, 1, 0, 0.25)
930    cr.rectangle(0, 0, 100, 50)
931    cr.fill()
932
933- name: 2d.imageData.put.modified
934  desc: putImageData() puts modified image data correctly
935  testing:
936  - 2d.imageData.put.normal
937  code: |
938    ctx.fillStyle = '#0f0';
939    ctx.fillRect(0, 0, 100, 50)
940    ctx.fillStyle = '#f00';
941    ctx.fillRect(45, 20, 10, 10)
942    var imgdata = ctx.getImageData(45, 20, 10, 10);
943    for (var i = 0, len = imgdata.width*imgdata.height*4; i < len; i += 4)
944    {
945        imgdata.data[i] = 0;
946        imgdata.data[i+1] = 255;
947    }
948    ctx.putImageData(imgdata, 45, 20);
949    @assert pixel 50,25 ==~ 0,255,0,255;
950  expected: green
951
952- name: 2d.imageData.put.dirty.zero
953  desc: putImageData() with zero-sized dirty rectangle puts nothing
954  testing:
955  - 2d.imageData.put.normal
956  code: |
957    ctx.fillStyle = '#f00';
958    ctx.fillRect(0, 0, 100, 50)
959    var imgdata = ctx.getImageData(0, 0, 100, 50);
960    ctx.fillStyle = '#0f0';
961    ctx.fillRect(0, 0, 100, 50)
962    ctx.putImageData(imgdata, 0, 0, 0, 0, 0, 0);
963    @assert pixel 50,25 ==~ 0,255,0,255;
964  expected: green
965
966- name: 2d.imageData.put.dirty.rect1
967  desc: putImageData() only modifies areas inside the dirty rectangle, using width
968    and height
969  testing:
970  - 2d.imageData.put.normal
971  code: |
972    ctx.fillStyle = '#f00';
973    ctx.fillRect(0, 0, 100, 50)
974    ctx.fillStyle = '#0f0';
975    ctx.fillRect(0, 0, 20, 20)
976
977    var imgdata = ctx.getImageData(0, 0, 100, 50);
978
979    ctx.fillStyle = '#0f0';
980    ctx.fillRect(0, 0, 100, 50)
981    ctx.fillStyle = '#f00';
982    ctx.fillRect(40, 20, 20, 20)
983    ctx.putImageData(imgdata, 40, 20, 0, 0, 20, 20);
984
985    @assert pixel 50,25 ==~ 0,255,0,255;
986    @assert pixel 35,25 ==~ 0,255,0,255;
987    @assert pixel 65,25 ==~ 0,255,0,255;
988    @assert pixel 50,15 ==~ 0,255,0,255;
989    @assert pixel 50,45 ==~ 0,255,0,255;
990  expected: green
991
992- name: 2d.imageData.put.dirty.rect2
993  desc: putImageData() only modifies areas inside the dirty rectangle, using x and
994    y
995  testing:
996  - 2d.imageData.put.normal
997  code: |
998    ctx.fillStyle = '#f00';
999    ctx.fillRect(0, 0, 100, 50)
1000    ctx.fillStyle = '#0f0';
1001    ctx.fillRect(60, 30, 20, 20)
1002
1003    var imgdata = ctx.getImageData(0, 0, 100, 50);
1004
1005    ctx.fillStyle = '#0f0';
1006    ctx.fillRect(0, 0, 100, 50)
1007    ctx.fillStyle = '#f00';
1008    ctx.fillRect(40, 20, 20, 20)
1009    ctx.putImageData(imgdata, -20, -10, 60, 30, 20, 20);
1010
1011    @assert pixel 50,25 ==~ 0,255,0,255;
1012    @assert pixel 35,25 ==~ 0,255,0,255;
1013    @assert pixel 65,25 ==~ 0,255,0,255;
1014    @assert pixel 50,15 ==~ 0,255,0,255;
1015    @assert pixel 50,45 ==~ 0,255,0,255;
1016  expected: green
1017
1018- name: 2d.imageData.put.dirty.negative
1019  desc: putImageData() handles negative-sized dirty rectangles correctly
1020  testing:
1021  - 2d.imageData.put.normal
1022  code: |
1023    ctx.fillStyle = '#f00';
1024    ctx.fillRect(0, 0, 100, 50)
1025    ctx.fillStyle = '#0f0';
1026    ctx.fillRect(0, 0, 20, 20)
1027
1028    var imgdata = ctx.getImageData(0, 0, 100, 50);
1029
1030    ctx.fillStyle = '#0f0';
1031    ctx.fillRect(0, 0, 100, 50)
1032    ctx.fillStyle = '#f00';
1033    ctx.fillRect(40, 20, 20, 20)
1034    ctx.putImageData(imgdata, 40, 20, 20, 20, -20, -20);
1035
1036    @assert pixel 50,25 ==~ 0,255,0,255;
1037    @assert pixel 35,25 ==~ 0,255,0,255;
1038    @assert pixel 65,25 ==~ 0,255,0,255;
1039    @assert pixel 50,15 ==~ 0,255,0,255;
1040    @assert pixel 50,45 ==~ 0,255,0,255;
1041  expected: green
1042
1043- name: 2d.imageData.put.dirty.outside
1044  desc: putImageData() handles dirty rectangles outside the canvas correctly
1045  testing:
1046  - 2d.imageData.put.normal
1047  code: |
1048    ctx.fillStyle = '#f00';
1049    ctx.fillRect(0, 0, 100, 50)
1050
1051    var imgdata = ctx.getImageData(0, 0, 100, 50);
1052
1053    ctx.fillStyle = '#0f0';
1054    ctx.fillRect(0, 0, 100, 50)
1055
1056    ctx.putImageData(imgdata, 100, 20, 20, 20, -20, -20);
1057    ctx.putImageData(imgdata, 200, 200, 0, 0, 100, 50);
1058    ctx.putImageData(imgdata, 40, 20, -30, -20, 30, 20);
1059    ctx.putImageData(imgdata, -30, 20, 0, 0, 30, 20);
1060
1061    @assert pixel 50,25 ==~ 0,255,0,255;
1062    @assert pixel 98,15 ==~ 0,255,0,255;
1063    @assert pixel 98,25 ==~ 0,255,0,255;
1064    @assert pixel 98,45 ==~ 0,255,0,255;
1065    @assert pixel 1,5 ==~ 0,255,0,255;
1066    @assert pixel 1,25 ==~ 0,255,0,255;
1067    @assert pixel 1,45 ==~ 0,255,0,255;
1068  expected: green
1069
1070- name: 2d.imageData.put.unchanged
1071  desc: putImageData(getImageData(...), ...) has no effect
1072  testing:
1073  - 2d.imageData.unchanged
1074  code: |
1075    var i = 0;
1076    for (var y = 0; y < 16; ++y) {
1077        for (var x = 0; x < 16; ++x, ++i) {
1078            ctx.fillStyle = 'rgba(' + i + ',' + (Math.floor(i*1.5) % 256) + ',' + (Math.floor(i*23.3) % 256) + ',' + (i/256) + ')';
1079            ctx.fillRect(x, y, 1, 1);
1080        }
1081    }
1082    var imgdata1 = ctx.getImageData(0.1, 0.2, 15.8, 15.9);
1083    var olddata = [];
1084    for (var i = 0; i < imgdata1.data.length; ++i)
1085        olddata[i] = imgdata1.data[i];
1086
1087    ctx.putImageData(imgdata1, 0.1, 0.2);
1088
1089    var imgdata2 = ctx.getImageData(0.1, 0.2, 15.8, 15.9);
1090    for (var i = 0; i < imgdata2.data.length; ++i) {
1091        @assert olddata[i] === imgdata2.data[i];
1092    }
1093
1094- name: 2d.imageData.put.unaffected
1095  desc: putImageData() is not affected by context state
1096  testing:
1097  - 2d.imageData.unaffected
1098  code: |
1099    ctx.fillStyle = '#0f0';
1100    ctx.fillRect(0, 0, 100, 50)
1101    var imgdata = ctx.getImageData(0, 0, 100, 50);
1102    ctx.fillStyle = '#f00';
1103    ctx.fillRect(0, 0, 100, 50)
1104    ctx.globalAlpha = 0.1;
1105    ctx.globalCompositeOperation = 'destination-atop';
1106    ctx.shadowColor = '#f00';
1107    ctx.shadowBlur = 1;
1108    ctx.translate(100, 50);
1109    ctx.scale(0.1, 0.1);
1110    ctx.putImageData(imgdata, 0, 0);
1111    @assert pixel 50,25 ==~ 0,255,0,255;
1112  expected: green
1113
1114- name: 2d.imageData.put.clip
1115  desc: putImageData() is not affected by clipping regions
1116  testing:
1117  - 2d.imageData.unaffected
1118  code: |
1119    ctx.fillStyle = '#0f0';
1120    ctx.fillRect(0, 0, 100, 50)
1121    var imgdata = ctx.getImageData(0, 0, 100, 50);
1122    ctx.fillStyle = '#f00';
1123    ctx.fillRect(0, 0, 100, 50)
1124    ctx.beginPath();
1125    ctx.rect(0, 0, 50, 50);
1126    ctx.clip();
1127    ctx.putImageData(imgdata, 0, 0);
1128    @assert pixel 25,25 ==~ 0,255,0,255;
1129    @assert pixel 75,25 ==~ 0,255,0,255;
1130  expected: green
1131
1132- name: 2d.imageData.put.path
1133  desc: putImageData() does not affect the current path
1134  testing:
1135  - 2d.imageData.put.normal
1136  code: |
1137    ctx.fillStyle = '#f00';
1138    ctx.fillRect(0, 0, 100, 50)
1139    ctx.rect(0, 0, 100, 50);
1140    var imgdata = ctx.getImageData(0, 0, 100, 50);
1141    ctx.putImageData(imgdata, 0, 0);
1142    ctx.fillStyle = '#0f0';
1143    ctx.fill();
1144    @assert pixel 50,25 ==~ 0,255,0,255;
1145  expected: green
1146
1147