5 ("onlyspace", " ", None),
6 ("space", " 100", 100),
7 ("whitespace", "\r\n\t\f100", 100),
9 ("minus", "-100", None),
10 ("octal", "0100", 100),
12 ("exp", "100e1", 100),
13 ("decimal", "100.999", 100),
14 ("percent", "100%", 100),
16 ("junk", "#!?", None),
17 ("trailingjunk", "100#!?", 100),
19 def gen(name, string, exp, code):
20 testing = ["size.nonnegativeinteger"]
22 testing.append("size.error")
23 code += "@assert canvas.width === 300;\n@assert canvas.height === 150;\n"
24 expected = "size 300 150"
26 code += "@assert canvas.width === %s;\n@assert canvas.height === %s;\n" % (exp, exp)
27 expected = "size %s %s" % (exp, exp)
29 # With "100%", Opera gets canvas.width = 100 but renders at 100% of the frame width,
30 # so check the CSS display width
31 code += '@assert window.getComputedStyle(canvas, null).getPropertyValue("width") === "%spx";\n' % (exp, )
33 code += "@assert canvas.getAttribute('width') === %r;\n" % string
34 code += "@assert canvas.getAttribute('height') === %r;\n" % string
37 expected = None # can't generate zero-sized PNGs for the expected image
39 return code, testing, expected
41 for name, string, exp in cases:
43 code, testing, expected = gen(name, string, exp, code)
44 # We need to replace \r with 
 because \r\n gets converted to \n in the HTML parser.
45 htmlString = string.replace('\r', '
')
47 "name": "size.attributes.parse.%s" % name,
48 "desc": "Parsing of non-negative integers",
50 "canvas": 'width="%s" height="%s"' % (htmlString, htmlString),
55 for name, string, exp in cases:
56 code = "canvas.setAttribute('width', %r);\ncanvas.setAttribute('height', %r);\n" % (string, string)
57 code, testing, expected = gen(name, string, exp, code)
59 "name": "size.attributes.setAttribute.%s" % name,
60 "desc": "Parsing of non-negative integers in setAttribute",
62 "canvas": 'width="50" height="50"',
68 state = [ # some non-default values to test with
69 ('strokeStyle', '"#ff0000"'),
70 ('fillStyle', '"#ff0000"'),
73 ('lineCap', '"round"'),
74 ('lineJoin', '"round"'),
79 ('shadowColor', '"#ff0000"'),
80 ('globalCompositeOperation', '"copy"'),
81 ('font', '"25px serif"'),
82 ('textAlign', '"center"'),
83 ('textBaseline', '"bottom"'),
85 for key,value in state:
87 'name': '2d.state.saverestore.%s' % key,
88 'desc': 'save()/restore() works for %s' % key,
89 'testing': [ '2d.state.%s' % key ],
91 """// Test that restore() undoes any modifications
92 var old = ctx.%(key)s;
94 ctx.%(key)s = %(value)s;
96 @assert ctx.%(key)s === old;
98 // Also test that save() doesn't modify the values
99 ctx.%(key)s = %(value)s;
101 // we're not interested in failures caused by get(set(x)) != x (e.g.
102 // from rounding), so compare against 'old' instead of against %(value)s
104 @assert ctx.%(key)s === old;
106 """ % { 'key':key, 'value':value }
110 'name': 'initial.reset.2dstate',
111 'desc': 'Resetting the canvas state resets 2D state variables',
112 'testing': [ 'initial.reset' ],
114 """canvas.width = 100;
118 default_val = ctx.%(key)s;
119 ctx.%(key)s = %(value)s;
121 @assert ctx.%(key)s === default_val;
122 """ % { 'key':key, 'value':value }
123 for key,value in state),
127 # Composite operation tests
128 # <http://lists.whatwg.org/htdig.cgi/whatwg-whatwg.org/2007-March/010608.html>
131 ('source-over', '1', '1-aA'),
132 ('destination-over', '1-aB', '1'),
133 ('source-in', 'aB', '0'),
134 ('destination-in', '0', 'aA'),
135 ('source-out', '1-aB', '0'),
136 ('destination-out', '0', '1-aA'),
137 ('source-atop', 'aB', '1-aA'),
138 ('destination-atop', '1-aB', 'aA'),
139 ('xor', '1-aB', '1-aA'),
141 ('lighter', '1', '1'),
144 # The ones that change the output when src = (0,0,0,0):
145 ops_trans = [ 'source-in', 'destination-in', 'source-out', 'destination-atop', 'copy' ];
147 def calc_output(A, B, FA_code, FB_code):
150 rA, gA, bA = RA*aA, GA*aA, BA*aA
151 rB, gB, bB = RB*aB, GB*aB, BB*aB
170 else: RO = GO = BO = 0
172 return (RO, GO, BO, aO)
176 return '%d,%d,%d,%d' % (round(r), round(g), round(b), round(a*255))
179 return '%f,%f,%f,%f' % (r/255., g/255., b/255., a)
181 for (name, src, dest) in [
182 ('solid', (255, 255, 0, 1.0), (0, 255, 255, 1.0)),
183 ('transparent', (0, 0, 255, 0.75), (0, 255, 0, 0.5)),
184 # catches the atop, xor and lighter bugs in Opera 9.10
186 for op, FA_code, FB_code in ops:
187 expected = calc_output(src, dest, FA_code, FB_code)
189 'name': '2d.composite.%s.%s' % (name, op),
190 'testing': [ '2d.composite.%s' % op ],
192 ctx.fillStyle = 'rgba%s';
193 ctx.fillRect(0, 0, 100, 50);
194 ctx.globalCompositeOperation = '%s';
195 ctx.fillStyle = 'rgba%s';
196 ctx.fillRect(0, 0, 100, 50);
197 @assert pixel 50,25 ==~ %s +/- 5;
198 """ % (dest, op, src, to_test(expected)),
199 'expected': """size 100 50
200 cr.set_source_rgba(%s)
201 cr.rectangle(0, 0, 100, 50)
203 """ % to_cairo(expected),
206 for (name, src, dest) in [ ('image', (255, 255, 0, 0.75), (0, 255, 255, 0.5)) ]:
207 for op, FA_code, FB_code in ops:
208 expected = calc_output(src, dest, FA_code, FB_code)
210 'name': '2d.composite.%s.%s' % (name, op),
211 'testing': [ '2d.composite.%s' % op ],
212 'images': [ 'yellow75.png' ],
214 ctx.fillStyle = 'rgba%s';
215 ctx.fillRect(0, 0, 100, 50);
216 ctx.globalCompositeOperation = '%s';
217 ctx.drawImage(document.getElementById('yellow75.png'), 0, 0);
218 @assert pixel 50,25 ==~ %s +/- 5;
219 """ % (dest, op, to_test(expected)),
220 'expected': """size 100 50
221 cr.set_source_rgba(%s)
222 cr.rectangle(0, 0, 100, 50)
224 """ % to_cairo(expected),
227 for (name, src, dest) in [ ('canvas', (255, 255, 0, 0.75), (0, 255, 255, 0.5)) ]:
228 for op, FA_code, FB_code in ops:
229 expected = calc_output(src, dest, FA_code, FB_code)
231 'name': '2d.composite.%s.%s' % (name, op),
232 'testing': [ '2d.composite.%s' % op ],
233 'images': [ 'yellow75.png' ],
235 var canvas2 = document.createElement('canvas');
236 canvas2.width = canvas.width;
237 canvas2.height = canvas.height;
238 var ctx2 = canvas2.getContext('2d');
239 ctx2.drawImage(document.getElementById('yellow75.png'), 0, 0);
240 ctx.fillStyle = 'rgba%s';
241 ctx.fillRect(0, 0, 100, 50);
242 ctx.globalCompositeOperation = '%s';
243 ctx.drawImage(canvas2, 0, 0);
244 @assert pixel 50,25 ==~ %s +/- 5;
245 """ % (dest, op, to_test(expected)),
246 'expected': """size 100 50
247 cr.set_source_rgba(%s)
248 cr.rectangle(0, 0, 100, 50)
250 """ % to_cairo(expected),
254 for (name, src, dest) in [ ('uncovered.fill', (0, 0, 255, 0.75), (0, 255, 0, 0.5)) ]:
255 for op, FA_code, FB_code in ops:
256 if op not in ops_trans: continue
257 expected0 = calc_output((0,0,0,0.0), dest, FA_code, FB_code)
259 'name': '2d.composite.%s.%s' % (name, op),
260 'desc': 'fill() draws pixels not covered by the source object as (0,0,0,0), and does not leave the pixels unchanged.',
261 'testing': [ '2d.composite.%s' % op ],
263 ctx.fillStyle = 'rgba%s';
264 ctx.fillRect(0, 0, 100, 50);
265 ctx.globalCompositeOperation = '%s';
266 ctx.fillStyle = 'rgba%s';
267 ctx.translate(0, 25);
268 ctx.fillRect(0, 50, 100, 50);
269 @assert pixel 50,25 ==~ %s +/- 5;
270 """ % (dest, op, src, to_test(expected0)),
271 'expected': """size 100 50
272 cr.set_source_rgba(%s)
273 cr.rectangle(0, 0, 100, 50)
275 """ % (to_cairo(expected0)),
278 for (name, src, dest) in [ ('uncovered.image', (255, 255, 0, 1.0), (0, 255, 255, 0.5)) ]:
279 for op, FA_code, FB_code in ops:
280 if op not in ops_trans: continue
281 expected0 = calc_output((0,0,0,0.0), dest, FA_code, FB_code)
283 'name': '2d.composite.%s.%s' % (name, op),
284 'desc': 'drawImage() draws pixels not covered by the source object as (0,0,0,0), and does not leave the pixels unchanged.',
285 'testing': [ '2d.composite.%s' % op ],
286 'images': [ 'yellow.png' ],
288 ctx.fillStyle = 'rgba%s';
289 ctx.fillRect(0, 0, 100, 50);
290 ctx.globalCompositeOperation = '%s';
291 ctx.drawImage(document.getElementById('yellow.png'), 40, 40, 10, 10, 40, 50, 10, 10);
292 @assert pixel 15,15 ==~ %s +/- 5;
293 @assert pixel 50,25 ==~ %s +/- 5;
294 """ % (dest, op, to_test(expected0), to_test(expected0)),
295 'expected': """size 100 50
296 cr.set_source_rgba(%s)
297 cr.rectangle(0, 0, 100, 50)
299 """ % (to_cairo(expected0)),
302 for (name, src, dest) in [ ('uncovered.nocontext', (255, 255, 0, 1.0), (0, 255, 255, 0.5)) ]:
303 for op, FA_code, FB_code in ops:
304 if op not in ops_trans: continue
305 expected0 = calc_output((0,0,0,0.0), dest, FA_code, FB_code)
307 'name': '2d.composite.%s.%s' % (name, op),
308 'desc': 'drawImage() of a canvas with no context draws pixels as (0,0,0,0), and does not leave the pixels unchanged.',
309 'testing': [ '2d.composite.%s' % op ],
311 ctx.fillStyle = 'rgba%s';
312 ctx.fillRect(0, 0, 100, 50);
313 ctx.globalCompositeOperation = '%s';
314 var canvas2 = document.createElement('canvas');
315 ctx.drawImage(canvas2, 0, 0);
316 @assert pixel 50,25 ==~ %s +/- 5;
317 """ % (dest, op, to_test(expected0)),
318 'expected': """size 100 50
319 cr.set_source_rgba(%s)
320 cr.rectangle(0, 0, 100, 50)
322 """ % (to_cairo(expected0)),
325 for (name, src, dest) in [ ('uncovered.pattern', (255, 255, 0, 1.0), (0, 255, 255, 0.5)) ]:
326 for op, FA_code, FB_code in ops:
327 if op not in ops_trans: continue
328 expected0 = calc_output((0,0,0,0.0), dest, FA_code, FB_code)
330 'name': '2d.composite.%s.%s' % (name, op),
331 'desc': 'Pattern fill() draws pixels not covered by the source object as (0,0,0,0), and does not leave the pixels unchanged.',
332 'testing': [ '2d.composite.%s' % op ],
333 'images': [ 'yellow.png' ],
335 ctx.fillStyle = 'rgba%s';
336 ctx.fillRect(0, 0, 100, 50);
337 ctx.globalCompositeOperation = '%s';
338 ctx.fillStyle = ctx.createPattern(document.getElementById('yellow.png'), 'no-repeat');
339 ctx.fillRect(0, 50, 100, 50);
340 @assert pixel 50,25 ==~ %s +/- 5;
341 """ % (dest, op, to_test(expected0)),
342 'expected': """size 100 50
343 cr.set_source_rgba(%s)
344 cr.rectangle(0, 0, 100, 50)
346 """ % (to_cairo(expected0)),
349 for op, FA_code, FB_code in ops:
351 'name': '2d.composite.clip.%s' % (op),
352 'desc': 'fill() does not affect pixels outside the clip region.',
353 'testing': [ '2d.composite.%s' % op ],
355 ctx.fillStyle = '#0f0';
356 ctx.fillRect(0, 0, 100, 50);
357 ctx.globalCompositeOperation = '%s';
358 ctx.rect(-20, -20, 10, 10);
360 ctx.fillStyle = '#f00';
361 ctx.fillRect(0, 0, 50, 50);
362 @assert pixel 25,25 == 0,255,0,255;
363 @assert pixel 75,25 == 0,255,0,255;
369 # Color parsing tests
371 # Try most of the CSS3 Color <color> values - http://www.w3.org/TR/css3-color/#colorunits
372 big_float = '1' + ('0' * 39)
373 big_double = '1' + ('0' * 310)
374 for name, string, r,g,b,a, notes in [
375 ('html4', 'limE', 0,255,0,255, ""),
376 ('hex3', '#0f0', 0,255,0,255, ""),
377 ('hex4', '#0f0f', 0,255,0,255, ""),
378 ('hex6', '#00fF00', 0,255,0,255, ""),
379 ('hex8', '#00ff00ff', 0,255,0,255, ""),
380 ('rgb-num', 'rgb(0,255,0)', 0,255,0,255, ""),
381 ('rgb-clamp-1', 'rgb(-1000, 1000, -1000)', 0,255,0,255, 'Assumes colors are clamped to [0,255].'),
382 ('rgb-clamp-2', 'rgb(-200%, 200%, -200%)', 0,255,0,255, 'Assumes colors are clamped to [0,255].'),
383 ('rgb-clamp-3', 'rgb(-2147483649, 4294967298, -18446744073709551619)', 0,255,0,255, 'Assumes colors are clamped to [0,255].'),
384 ('rgb-clamp-4', 'rgb(-'+big_float+', '+big_float+', -'+big_float+')', 0,255,0,255, 'Assumes colors are clamped to [0,255].'),
385 ('rgb-clamp-5', 'rgb(-'+big_double+', '+big_double+', -'+big_double+')', 0,255,0,255, 'Assumes colors are clamped to [0,255].'),
386 ('rgb-percent', 'rgb(0% ,100% ,0%)', 0,255,0,255, 'CSS3 Color says "The integer value 255 corresponds to 100%". (In particular, it is not 254...)'),
387 ('rgb-eof', 'rgb(0, 255, 0', 0,255,0,255, ""), # see CSS2.1 4.2 "Unexpected end of style sheet"
388 ('rgba-solid-1', 'rgba( 0 , 255 , 0 , 1 )', 0,255,0,255, ""),
389 ('rgba-solid-2', 'rgba( 0 , 255 , 0 , 1.0 )', 0,255,0,255, ""),
390 ('rgba-solid-3', 'rgba( 0 , 255 , 0 , +1 )', 0,255,0,255, ""),
391 ('rgba-solid-4', 'rgba( -0 , 255 , +0 , 1 )', 0,255,0,255, ""),
392 ('rgba-num-1', 'rgba( 0 , 255 , 0 , .499 )', 0,255,0,127, ""),
393 ('rgba-num-2', 'rgba( 0 , 255 , 0 , 0.499 )', 0,255,0,127, ""),
394 ('rgba-percent', 'rgba(0%,100%,0%,0.499)', 0,255,0,127, ""), # 0.499*255 rounds to 127, both down and nearest, so it should be safe
395 ('rgba-clamp-1', 'rgba(0, 255, 0, -2)', 0,0,0,0, ""),
396 ('rgba-clamp-2', 'rgba(0, 255, 0, 2)', 0,255,0,255, ""),
397 ('rgba-eof', 'rgba(0, 255, 0, 1', 0,255,0,255, ""),
398 ('transparent-1', 'transparent', 0,0,0,0, ""),
399 ('transparent-2', 'TrAnSpArEnT', 0,0,0,0, ""),
400 ('hsl-1', 'hsl(120, 100%, 50%)', 0,255,0,255, ""),
401 ('hsl-2', 'hsl( -240 , 100% , 50% )', 0,255,0,255, ""),
402 ('hsl-3', 'hsl(360120, 100%, 50%)', 0,255,0,255, ""),
403 ('hsl-4', 'hsl(-360240, 100%, 50%)', 0,255,0,255, ""),
404 ('hsl-5', 'hsl(120.0, 100.0%, 50.0%)', 0,255,0,255, ""),
405 ('hsl-6', 'hsl(+120, +100%, +50%)', 0,255,0,255, ""),
406 ('hsl-clamp-1', 'hsl(120, 200%, 50%)', 0,255,0,255, ""),
407 ('hsl-clamp-2', 'hsl(120, -200%, 49.9%)', 127,127,127,255, ""),
408 ('hsl-clamp-3', 'hsl(120, 100%, 200%)', 255,255,255,255, ""),
409 ('hsl-clamp-4', 'hsl(120, 100%, -200%)', 0,0,0,255, ""),
410 ('hsla-1', 'hsla(120, 100%, 50%, 0.499)', 0,255,0,127, ""),
411 ('hsla-2', 'hsla( 120.0 , 100.0% , 50.0% , 1 )', 0,255,0,255, ""),
412 ('hsla-clamp-1', 'hsla(120, 200%, 50%, 1)', 0,255,0,255, ""),
413 ('hsla-clamp-2', 'hsla(120, -200%, 49.9%, 1)', 127,127,127,255, ""),
414 ('hsla-clamp-3', 'hsla(120, 100%, 200%, 1)', 255,255,255,255, ""),
415 ('hsla-clamp-4', 'hsla(120, 100%, -200%, 1)', 0,0,0,255, ""),
416 ('hsla-clamp-5', 'hsla(120, 100%, 50%, 2)', 0,255,0,255, ""),
417 ('hsla-clamp-6', 'hsla(120, 100%, 0%, -2)', 0,0,0,0, ""),
418 ('svg-1', 'gray', 128,128,128,255, ""),
419 ('svg-2', 'grey', 128,128,128,255, ""),
420 # css-color-4 rgb() color function
421 # https://drafts.csswg.org/css-color/#numeric-rgb
422 ('css-color-4-rgb-1', 'rgb(0, 255.0, 0)', 0,255,0,255, ""),
423 ('css-color-4-rgb-2', 'rgb(0, 255, 0, 0.2)', 0,255,0,51, ""),
424 ('css-color-4-rgb-3', 'rgb(0, 255, 0, 20%)', 0,255,0,51, ""),
425 ('css-color-4-rgb-4', 'rgb(0 255 0)', 0,255,0,255, ""),
426 ('css-color-4-rgb-5', 'rgb(0 255 0 / 0.2)', 0,255,0,51, ""),
427 ('css-color-4-rgb-6', 'rgb(0 255 0 / 20%)', 0,255,0,51, ""),
428 ('css-color-4-rgba-1', 'rgba(0, 255.0, 0)', 0,255,0,255, ""),
429 ('css-color-4-rgba-2', 'rgba(0, 255, 0, 0.2)', 0,255,0,51, ""),
430 ('css-color-4-rgba-3', 'rgba(0, 255, 0, 20%)', 0,255,0,51, ""),
431 ('css-color-4-rgba-4', 'rgba(0 255 0)', 0,255,0,255, ""),
432 ('css-color-4-rgba-5', 'rgba(0 255 0 / 0.2)', 0,255,0,51, ""),
433 ('css-color-4-rgba-6', 'rgba(0 255 0 / 20%)', 0,255,0,51, ""),
434 # css-color-4 hsl() color function
435 # https://drafts.csswg.org/css-color/#the-hsl-notation
436 ('css-color-4-hsl-1', 'hsl(120 100.0% 50.0%)', 0,255,0,255, ""),
437 ('css-color-4-hsl-2', 'hsl(120 100.0% 50.0% / 0.2)', 0,255,0,51, ""),
438 ('css-color-4-hsl-3', 'hsl(120.0, 100.0%, 50.0%, 0.2)', 0,255,0,51, ""),
439 ('css-color-4-hsl-4', 'hsl(120.0, 100.0%, 50.0%, 20%)', 0,255,0,51, ""),
440 ('css-color-4-hsl-5', 'hsl(120deg, 100.0%, 50.0%, 0.2)', 0,255,0,51, ""),
441 ('css-color-4-hsl-6', 'hsl(120deg, 100.0%, 50.0%)', 0,255,0,255, ""),
442 ('css-color-4-hsl-7', 'hsl(133.33333333grad, 100.0%, 50.0%)', 0,255,0,255, ""),
443 ('css-color-4-hsl-8', 'hsl(2.0943951024rad, 100.0%, 50.0%)', 0,255,0,255, ""),
444 ('css-color-4-hsl-9', 'hsl(0.3333333333turn, 100.0%, 50.0%)', 0,255,0,255, ""),
445 ('css-color-4-hsla-1', 'hsl(120 100.0% 50.0%)', 0,255,0,255, ""),
446 ('css-color-4-hsla-2', 'hsl(120 100.0% 50.0% / 0.2)', 0,255,0,51, ""),
447 ('css-color-4-hsla-3', 'hsl(120.0, 100.0%, 50.0%, 0.2)', 0,255,0,51, ""),
448 ('css-color-4-hsla-4', 'hsl(120.0, 100.0%, 50.0%, 20%)', 0,255,0,51, ""),
449 ('css-color-4-hsla-5', 'hsl(120deg, 100.0%, 50.0%, 0.2)', 0,255,0,51, ""),
450 ('css-color-4-hsla-6', 'hsl(120deg, 100.0%, 50.0%)', 0,255,0,255, ""),
451 ('css-color-4-hsla-7', 'hsl(133.33333333grad, 100.0%, 50.0%)', 0,255,0,255, ""),
452 ('css-color-4-hsla-8', 'hsl(2.0943951024rad, 100.0%, 50.0%)', 0,255,0,255, ""),
453 ('css-color-4-hsla-9', 'hsl(0.3333333333turn, 100.0%, 50.0%)', 0,255,0,255, ""),
454 # currentColor is handled later
456 # TODO: test by retrieving fillStyle, instead of actually drawing?
457 # TODO: test strokeStyle, shadowColor in the same way
459 'name': '2d.fillStyle.parse.%s' % name,
460 'testing': [ '2d.colors.parse' ],
463 ctx.fillStyle = '#f00';
464 ctx.fillStyle = '%s';
465 ctx.fillRect(0, 0, 100, 50);
466 @assert pixel 50,25 == %d,%d,%d,%d;
467 """ % (string, r,g,b,a),
468 'expected': """size 100 50
469 cr.set_source_rgba(%f, %f, %f, %f)
470 cr.rectangle(0, 0, 100, 50)
472 """ % (r/255., g/255., b/255., a/255.),
476 # Also test that invalid colors are ignored
477 for name, string in [
484 ('hex7', '#ff0000f'),
485 ('hex8', '#fg0000ff'),
486 ('rgb-1', 'rgb(255.0, 0, 0,)'),
487 ('rgb-2', 'rgb(100%, 0, 0)'),
488 ('rgb-3', 'rgb(255, - 1, 0)'),
489 ('rgba-1', 'rgba(100%, 0, 0, 1)'),
490 ('rgba-2', 'rgba(255, 0, 0, 1. 0)'),
491 ('rgba-3', 'rgba(255, 0, 0, 1.)'),
492 ('rgba-4', 'rgba(255, 0, 0, '),
493 ('rgba-5', 'rgba(255, 0, 0, 1,)'),
494 ('hsl-1', 'hsl(0%, 100%, 50%)'),
495 ('hsl-2', 'hsl(z, 100%, 50%)'),
496 ('hsl-3', 'hsl(0, 0, 50%)'),
497 ('hsl-4', 'hsl(0, 100%, 0)'),
498 ('hsl-5', 'hsl(0, 100.%, 50%)'),
499 ('hsl-6', 'hsl(0, 100%, 50%,)'),
500 ('hsla-1', 'hsla(0%, 100%, 50%, 1)'),
501 ('hsla-2', 'hsla(0, 0, 50%, 1)'),
502 ('hsla-3', 'hsla(0, 0, 50%, 1,)'),
503 ('name-1', 'darkbrown'),
504 ('name-2', 'firebrick1'),
505 ('name-3', 'red blue'),
508 # css-color-4 color function
509 # comma and comma-less expressions should not mix together.
510 ('css-color-4-rgb-1', 'rgb(255, 0, 0 / 1)'),
511 ('css-color-4-rgb-2', 'rgb(255 0 0, 1)'),
512 ('css-color-4-rgb-3', 'rgb(255, 0 0)'),
513 ('css-color-4-rgba-1', 'rgba(255, 0, 0 / 1)'),
514 ('css-color-4-rgba-2', 'rgba(255 0 0, 1)'),
515 ('css-color-4-rgba-3', 'rgba(255, 0 0)'),
516 ('css-color-4-hsl-1', 'hsl(0, 100%, 50% / 1)'),
517 ('css-color-4-hsl-2', 'hsl(0 100% 50%, 1)'),
518 ('css-color-4-hsl-3', 'hsl(0, 100% 50%)'),
519 ('css-color-4-hsla-1', 'hsla(0, 100%, 50% / 1)'),
520 ('css-color-4-hsla-2', 'hsla(0 100% 50%, 1)'),
521 ('css-color-4-hsla-3', 'hsla(0, 100% 50%)'),
523 ('css-color-4-rgb-4', 'rgb(0 0 0 /)'),
524 ('css-color-4-rgb-5', 'rgb(0, 0, 0 /)'),
525 ('css-color-4-hsl-4', 'hsl(0 100% 50% /)'),
526 ('css-color-4-hsl-5', 'hsl(0, 100%, 50% /)'),
529 'name': '2d.fillStyle.parse.invalid.%s' % name,
530 'testing': [ '2d.colors.parse' ],
532 ctx.fillStyle = '#0f0';
533 try { ctx.fillStyle = '%s'; } catch (e) { } // this shouldn't throw, but it shouldn't matter here if it does
534 ctx.fillRect(0, 0, 100, 50);
535 @assert pixel 50,25 == 0,255,0,255;
541 # Some can't have positive tests, only negative tests, because we don't know what color they're meant to be
542 for name, string in [
543 ('system', 'ThreeDDarkShadow'),
544 #('flavor', 'flavor'), # removed from latest CSS3 Color drafts
547 'name': '2d.fillStyle.parse.%s' % name,
548 'testing': [ '2d.colors.parse' ],
550 ctx.fillStyle = '#f00';
551 ctx.fillStyle = '%s';
552 @assert ctx.fillStyle =~ /^#(?!(FF0000|ff0000|f00)$)/; // test that it's not red