From 26a029d407be480d791972afb5975cf62c9360a6 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Fri, 19 Apr 2024 02:47:55 +0200 Subject: Adding upstream version 124.0.1. Signed-off-by: Daniel Baumann --- .../tests/html/canvas/tools/yaml/element/meta.yaml | 539 +++++++++++++++++++++ .../tools/yaml/element/the-canvas-element.yaml | 143 ++++++ 2 files changed, 682 insertions(+) create mode 100644 testing/web-platform/tests/html/canvas/tools/yaml/element/meta.yaml create mode 100644 testing/web-platform/tests/html/canvas/tools/yaml/element/the-canvas-element.yaml (limited to 'testing/web-platform/tests/html/canvas/tools/yaml/element') diff --git a/testing/web-platform/tests/html/canvas/tools/yaml/element/meta.yaml b/testing/web-platform/tests/html/canvas/tools/yaml/element/meta.yaml new file mode 100644 index 0000000000..5fd8b68498 --- /dev/null +++ b/testing/web-platform/tests/html/canvas/tools/yaml/element/meta.yaml @@ -0,0 +1,539 @@ +- meta: | + cases = [ + ("zero", "0", 0), + ("empty", "", None), + ("onlyspace", " ", None), + ("space", " 100", 100), + ("whitespace", "\r\n\t\f100", 100), + ("plus", "+100", 100), + ("minus", "-100", None), + ("octal", "0100", 100), + ("hex", "0x100", 0), + ("exp", "100e1", 100), + ("decimal", "100.999", 100), + ("percent", "100%", 100), + ("em", "100em", 100), + ("junk", "#!?", None), + ("trailingjunk", "100#!?", 100), + ] + def gen(name, string, exp, code): + if exp is None: + code += "@assert canvas.width === 300;\n@assert canvas.height === 150;\n" + expected = "size 300 150" + else: + code += "@assert canvas.width === %s;\n@assert canvas.height === %s;\n" % (exp, exp) + expected = "size %s %s" % (exp, exp) + + # With "100%", Opera gets canvas.width = 100 but renders at 100% of the frame width, + # so check the CSS display width + code += '@assert window.getComputedStyle(canvas, null).getPropertyValue("width") === "%spx";\n' % (exp, ) + + code += "@assert canvas.getAttribute('width') === %r;\n" % string + code += "@assert canvas.getAttribute('height') === %r;\n" % string + + if exp == 0: + expected = None # can't generate zero-sized PNGs for the expected image + + return code, expected + + for name, string, exp in cases: + code = "" + code, expected = gen(name, string, exp, code) + # We need to replace \r with because \r\n gets converted to \n in the HTML parser. + htmlString = string.replace('\r', ' ') + tests.append( { + "name": "2d.canvas.host.size.attributes.parse.%s" % name, + "desc": "Parsing of non-negative integers", + "size": '%s, %s' % (htmlString, htmlString), + "code": code, + "expected": expected + } ) + + for name, string, exp in cases: + code = "canvas.setAttribute('width', %r);\ncanvas.setAttribute('height', %r);\n" % (string, string) + code, expected = gen(name, string, exp, code) + tests.append( { + "name": "2d.canvas.host.size.attributes.setAttribute.%s" % name, + "desc": "Parsing of non-negative integers in setAttribute", + "size": '50, 50', + "code": code, + "expected": expected + } ) + +- meta: | + state = [ # some non-default values to test with + ('strokeStyle', '"#ff0000"'), + ('fillStyle', '"#ff0000"'), + ('globalAlpha', 0.5), + ('lineWidth', 0.5), + ('lineCap', '"round"'), + ('lineJoin', '"round"'), + ('miterLimit', 0.5), + ('shadowOffsetX', 5), + ('shadowOffsetY', 5), + ('shadowBlur', 5), + ('shadowColor', '"#ff0000"'), + ('globalCompositeOperation', '"copy"'), + ('font', '"25px serif"'), + ('textAlign', '"center"'), + ('textBaseline', '"bottom"'), + ] + for key,value in state: + tests.append( { + 'name': '2d.state.saverestore.%s' % key, + 'desc': 'save()/restore() works for %s' % key, + 'code': + """// Test that restore() undoes any modifications + var old = ctx.%(key)s; + ctx.save(); + ctx.%(key)s = %(value)s; + ctx.restore(); + @assert ctx.%(key)s === old; + + // Also test that save() doesn't modify the values + ctx.%(key)s = %(value)s; + old = ctx.%(key)s; + // we're not interested in failures caused by get(set(x)) != x (e.g. + // from rounding), so compare against 'old' instead of against %(value)s + ctx.save(); + @assert ctx.%(key)s === old; + ctx.restore(); + """ % { 'key':key, 'value':value } + } ) + + tests.append( { + 'name': '2d.canvas.host.initial.reset.2dstate', + 'desc': 'Resetting the canvas state resets 2D state variables', + 'code': + """canvas.width = 100; + var default_val; + """ + "".join( + """ + default_val = ctx.%(key)s; + ctx.%(key)s = %(value)s; + canvas.width = 100; + @assert ctx.%(key)s === default_val; + """ % { 'key':key, 'value':value } + for key,value in state), + } ) + +- meta: | + # Composite operation tests + # + ops = [ + # name FA FB + ('source-over', '1', '1-aA'), + ('destination-over', '1-aB', '1'), + ('source-in', 'aB', '0'), + ('destination-in', '0', 'aA'), + ('source-out', '1-aB', '0'), + ('destination-out', '0', '1-aA'), + ('source-atop', 'aB', '1-aA'), + ('destination-atop', '1-aB', 'aA'), + ('xor', '1-aB', '1-aA'), + ('copy', '1', '0'), + ('lighter', '1', '1'), + ('clear', '0', '0'), + ] + + # The ones that change the output when src = (0,0,0,0): + ops_trans = [ 'source-in', 'destination-in', 'source-out', 'destination-atop', 'copy' ]; + + def calc_output(A, B, FA_code, FB_code): + (RA, GA, BA, aA) = A + (RB, GB, BB, aB) = B + rA, gA, bA = RA*aA, GA*aA, BA*aA + rB, gB, bB = RB*aB, GB*aB, BB*aB + + FA = eval(FA_code) + FB = eval(FB_code) + + rO = rA*FA + rB*FB + gO = gA*FA + gB*FB + bO = bA*FA + bB*FB + aO = aA*FA + aB*FB + + rO = min(255, rO) + gO = min(255, gO) + bO = min(255, bO) + aO = min(1, aO) + + if aO: + RO = rO / aO + GO = gO / aO + BO = bO / aO + else: RO = GO = BO = 0 + + return (RO, GO, BO, aO) + + def to_test(color): + r, g, b, a = color + return '%d,%d,%d,%d' % (round(r), round(g), round(b), round(a*255)) + def to_cairo(color): + r, g, b, a = color + return '%f,%f,%f,%f' % (r/255., g/255., b/255., a) + + for (name, src, dest) in [ + ('solid', (255, 255, 0, 1.0), (0, 255, 255, 1.0)), + ('transparent', (0, 0, 255, 0.75), (0, 255, 0, 0.5)), + # catches the atop, xor and lighter bugs in Opera 9.10 + ]: + for op, FA_code, FB_code in ops: + expected = calc_output(src, dest, FA_code, FB_code) + tests.append( { + 'name': '2d.composite.%s.%s' % (name, op), + 'code': """ + ctx.fillStyle = 'rgba%s'; + ctx.fillRect(0, 0, 100, 50); + ctx.globalCompositeOperation = '%s'; + ctx.fillStyle = 'rgba%s'; + ctx.fillRect(0, 0, 100, 50); + @assert pixel 50,25 ==~ %s +/- 5; + """ % (dest, op, src, to_test(expected)), + 'expected': """size 100 50 + cr.set_source_rgba(%s) + cr.rectangle(0, 0, 100, 50) + cr.fill() + """ % to_cairo(expected), + } ) + + for (name, src, dest) in [ ('image', (255, 255, 0, 0.75), (0, 255, 255, 0.5)) ]: + for op, FA_code, FB_code in ops: + expected = calc_output(src, dest, FA_code, FB_code) + tests.append( { + 'name': '2d.composite.%s.%s' % (name, op), + 'images': [ 'yellow75.png' ], + 'code': """ + ctx.fillStyle = 'rgba%s'; + ctx.fillRect(0, 0, 100, 50); + ctx.globalCompositeOperation = '%s'; + ctx.drawImage(document.getElementById('yellow75.png'), 0, 0); + @assert pixel 50,25 ==~ %s +/- 5; + """ % (dest, op, to_test(expected)), + 'expected': """size 100 50 + cr.set_source_rgba(%s) + cr.rectangle(0, 0, 100, 50) + cr.fill() + """ % to_cairo(expected), + } ) + + for (name, src, dest) in [ ('canvas', (255, 255, 0, 0.75), (0, 255, 255, 0.5)) ]: + for op, FA_code, FB_code in ops: + expected = calc_output(src, dest, FA_code, FB_code) + tests.append( { + 'name': '2d.composite.%s.%s' % (name, op), + 'images': [ 'yellow75.png' ], + 'code': """ + var canvas2 = document.createElement('canvas'); + canvas2.width = canvas.width; + canvas2.height = canvas.height; + var ctx2 = canvas2.getContext('2d'); + ctx2.drawImage(document.getElementById('yellow75.png'), 0, 0); + ctx.fillStyle = 'rgba%s'; + ctx.fillRect(0, 0, 100, 50); + ctx.globalCompositeOperation = '%s'; + ctx.drawImage(canvas2, 0, 0); + @assert pixel 50,25 ==~ %s +/- 5; + """ % (dest, op, to_test(expected)), + 'expected': """size 100 50 + cr.set_source_rgba(%s) + cr.rectangle(0, 0, 100, 50) + cr.fill() + """ % to_cairo(expected), + } ) + + + for (name, src, dest) in [ ('uncovered.fill', (0, 0, 255, 0.75), (0, 255, 0, 0.5)) ]: + for op, FA_code, FB_code in ops: + if op not in ops_trans: continue + expected0 = calc_output((0,0,0,0.0), dest, FA_code, FB_code) + tests.append( { + 'name': '2d.composite.%s.%s' % (name, op), + 'desc': 'fill() draws pixels not covered by the source object as (0,0,0,0), and does not leave the pixels unchanged.', + 'code': """ + ctx.fillStyle = 'rgba%s'; + ctx.fillRect(0, 0, 100, 50); + ctx.globalCompositeOperation = '%s'; + ctx.fillStyle = 'rgba%s'; + ctx.translate(0, 25); + ctx.fillRect(0, 50, 100, 50); + @assert pixel 50,25 ==~ %s +/- 5; + """ % (dest, op, src, to_test(expected0)), + 'expected': """size 100 50 + cr.set_source_rgba(%s) + cr.rectangle(0, 0, 100, 50) + cr.fill() + """ % (to_cairo(expected0)), + } ) + + for (name, src, dest) in [ ('uncovered.image', (255, 255, 0, 1.0), (0, 255, 255, 0.5)) ]: + for op, FA_code, FB_code in ops: + if op not in ops_trans: continue + expected0 = calc_output((0,0,0,0.0), dest, FA_code, FB_code) + tests.append( { + 'name': '2d.composite.%s.%s' % (name, op), + 'desc': 'drawImage() draws pixels not covered by the source object as (0,0,0,0), and does not leave the pixels unchanged.', + 'images': [ 'yellow.png' ], + 'code': """ + ctx.fillStyle = 'rgba%s'; + ctx.fillRect(0, 0, 100, 50); + ctx.globalCompositeOperation = '%s'; + ctx.drawImage(document.getElementById('yellow.png'), 40, 40, 10, 10, 40, 50, 10, 10); + @assert pixel 15,15 ==~ %s +/- 5; + @assert pixel 50,25 ==~ %s +/- 5; + """ % (dest, op, to_test(expected0), to_test(expected0)), + 'expected': """size 100 50 + cr.set_source_rgba(%s) + cr.rectangle(0, 0, 100, 50) + cr.fill() + """ % (to_cairo(expected0)), + } ) + + for (name, src, dest) in [ ('uncovered.nocontext', (255, 255, 0, 1.0), (0, 255, 255, 0.5)) ]: + for op, FA_code, FB_code in ops: + if op not in ops_trans: continue + expected0 = calc_output((0,0,0,0.0), dest, FA_code, FB_code) + tests.append( { + 'name': '2d.composite.%s.%s' % (name, op), + 'desc': 'drawImage() of a canvas with no context draws pixels as (0,0,0,0), and does not leave the pixels unchanged.', + 'code': """ + ctx.fillStyle = 'rgba%s'; + ctx.fillRect(0, 0, 100, 50); + ctx.globalCompositeOperation = '%s'; + var canvas2 = document.createElement('canvas'); + ctx.drawImage(canvas2, 0, 0); + @assert pixel 50,25 ==~ %s +/- 5; + """ % (dest, op, to_test(expected0)), + 'expected': """size 100 50 + cr.set_source_rgba(%s) + cr.rectangle(0, 0, 100, 50) + cr.fill() + """ % (to_cairo(expected0)), + } ) + + for (name, src, dest) in [ ('uncovered.pattern', (255, 255, 0, 1.0), (0, 255, 255, 0.5)) ]: + for op, FA_code, FB_code in ops: + if op not in ops_trans: continue + expected0 = calc_output((0,0,0,0.0), dest, FA_code, FB_code) + tests.append( { + 'name': '2d.composite.%s.%s' % (name, op), + 'desc': 'Pattern fill() draws pixels not covered by the source object as (0,0,0,0), and does not leave the pixels unchanged.', + 'images': [ 'yellow.png' ], + 'code': """ + ctx.fillStyle = 'rgba%s'; + ctx.fillRect(0, 0, 100, 50); + ctx.globalCompositeOperation = '%s'; + ctx.fillStyle = ctx.createPattern(document.getElementById('yellow.png'), 'no-repeat'); + ctx.fillRect(0, 50, 100, 50); + @assert pixel 50,25 ==~ %s +/- 5; + """ % (dest, op, to_test(expected0)), + 'expected': """size 100 50 + cr.set_source_rgba(%s) + cr.rectangle(0, 0, 100, 50) + cr.fill() + """ % (to_cairo(expected0)), + } ) + + for op, FA_code, FB_code in ops: + tests.append( { + 'name': '2d.composite.clip.%s' % (op), + 'desc': 'fill() does not affect pixels outside the clip region.', + 'code': """ + ctx.fillStyle = '#0f0'; + ctx.fillRect(0, 0, 100, 50); + ctx.globalCompositeOperation = '%s'; + ctx.rect(-20, -20, 10, 10); + ctx.clip(); + ctx.fillStyle = '#f00'; + ctx.fillRect(0, 0, 50, 50); + @assert pixel 25,25 == 0,255,0,255; + @assert pixel 75,25 == 0,255,0,255; + """ % (op), + 'expected': 'green' + } ) + +- meta: | + # Color parsing tests + + # Try most of the CSS3 Color values - http://www.w3.org/TR/css3-color/#colorunits + big_float = '1' + ('0' * 39) + big_double = '1' + ('0' * 310) + for name, string, r,g,b,a, notes in [ + ('html4', 'limE', 0,255,0,255, ""), + ('hex3', '#0f0', 0,255,0,255, ""), + ('hex4', '#0f0f', 0,255,0,255, ""), + ('hex6', '#00fF00', 0,255,0,255, ""), + ('hex8', '#00ff00ff', 0,255,0,255, ""), + ('rgb-num', 'rgb(0,255,0)', 0,255,0,255, ""), + ('rgb-clamp-1', 'rgb(-1000, 1000, -1000)', 0,255,0,255, 'Assumes colors are clamped to [0,255].'), + ('rgb-clamp-2', 'rgb(-200%, 200%, -200%)', 0,255,0,255, 'Assumes colors are clamped to [0,255].'), + ('rgb-clamp-3', 'rgb(-2147483649, 4294967298, -18446744073709551619)', 0,255,0,255, 'Assumes colors are clamped to [0,255].'), + ('rgb-clamp-4', 'rgb(-'+big_float+', '+big_float+', -'+big_float+')', 0,255,0,255, 'Assumes colors are clamped to [0,255].'), + ('rgb-clamp-5', 'rgb(-'+big_double+', '+big_double+', -'+big_double+')', 0,255,0,255, 'Assumes colors are clamped to [0,255].'), + ('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...)'), + ('rgb-eof', 'rgb(0, 255, 0', 0,255,0,255, ""), # see CSS2.1 4.2 "Unexpected end of style sheet" + ('rgba-solid-1', 'rgba( 0 , 255 , 0 , 1 )', 0,255,0,255, ""), + ('rgba-solid-2', 'rgba( 0 , 255 , 0 , 1.0 )', 0,255,0,255, ""), + ('rgba-solid-3', 'rgba( 0 , 255 , 0 , +1 )', 0,255,0,255, ""), + ('rgba-solid-4', 'rgba( -0 , 255 , +0 , 1 )', 0,255,0,255, ""), + ('rgba-num-1', 'rgba( 0 , 255 , 0 , .499 )', 0,255,0,127, ""), + ('rgba-num-2', 'rgba( 0 , 255 , 0 , 0.499 )', 0,255,0,127, ""), + ('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 + ('rgba-clamp-1', 'rgba(0, 255, 0, -2)', 0,0,0,0, ""), + ('rgba-clamp-2', 'rgba(0, 255, 0, 2)', 0,255,0,255, ""), + ('rgba-eof', 'rgba(0, 255, 0, 1', 0,255,0,255, ""), + ('transparent-1', 'transparent', 0,0,0,0, ""), + ('transparent-2', 'TrAnSpArEnT', 0,0,0,0, ""), + ('hsl-1', 'hsl(120, 100%, 50%)', 0,255,0,255, ""), + ('hsl-2', 'hsl( -240 , 100% , 50% )', 0,255,0,255, ""), + ('hsl-3', 'hsl(360120, 100%, 50%)', 0,255,0,255, ""), + ('hsl-4', 'hsl(-360240, 100%, 50%)', 0,255,0,255, ""), + ('hsl-5', 'hsl(120.0, 100.0%, 50.0%)', 0,255,0,255, ""), + ('hsl-6', 'hsl(+120, +100%, +50%)', 0,255,0,255, ""), + ('hsl-clamp-1', 'hsl(120, 200%, 50%)', 0,255,0,255, ""), + ('hsl-clamp-2', 'hsl(120, -200%, 49.9%)', 127,127,127,255, ""), + ('hsl-clamp-3', 'hsl(120, 100%, 200%)', 255,255,255,255, ""), + ('hsl-clamp-4', 'hsl(120, 100%, -200%)', 0,0,0,255, ""), + ('hsla-1', 'hsla(120, 100%, 50%, 0.499)', 0,255,0,127, ""), + ('hsla-2', 'hsla( 120.0 , 100.0% , 50.0% , 1 )', 0,255,0,255, ""), + ('hsla-clamp-1', 'hsla(120, 200%, 50%, 1)', 0,255,0,255, ""), + ('hsla-clamp-2', 'hsla(120, -200%, 49.9%, 1)', 127,127,127,255, ""), + ('hsla-clamp-3', 'hsla(120, 100%, 200%, 1)', 255,255,255,255, ""), + ('hsla-clamp-4', 'hsla(120, 100%, -200%, 1)', 0,0,0,255, ""), + ('hsla-clamp-5', 'hsla(120, 100%, 50%, 2)', 0,255,0,255, ""), + ('hsla-clamp-6', 'hsla(120, 100%, 0%, -2)', 0,0,0,0, ""), + ('svg-1', 'gray', 128,128,128,255, ""), + ('svg-2', 'grey', 128,128,128,255, ""), + # css-color-4 rgb() color function + # https://drafts.csswg.org/css-color/#numeric-rgb + ('css-color-4-rgb-1', 'rgb(0, 255.0, 0)', 0,255,0,255, ""), + ('css-color-4-rgb-2', 'rgb(0, 255, 0, 0.2)', 0,255,0,51, ""), + ('css-color-4-rgb-3', 'rgb(0, 255, 0, 20%)', 0,255,0,51, ""), + ('css-color-4-rgb-4', 'rgb(0 255 0)', 0,255,0,255, ""), + ('css-color-4-rgb-5', 'rgb(0 255 0 / 0.2)', 0,255,0,51, ""), + ('css-color-4-rgb-6', 'rgb(0 255 0 / 20%)', 0,255,0,51, ""), + ('css-color-4-rgba-1', 'rgba(0, 255.0, 0)', 0,255,0,255, ""), + ('css-color-4-rgba-2', 'rgba(0, 255, 0, 0.2)', 0,255,0,51, ""), + ('css-color-4-rgba-3', 'rgba(0, 255, 0, 20%)', 0,255,0,51, ""), + ('css-color-4-rgba-4', 'rgba(0 255 0)', 0,255,0,255, ""), + ('css-color-4-rgba-5', 'rgba(0 255 0 / 0.2)', 0,255,0,51, ""), + ('css-color-4-rgba-6', 'rgba(0 255 0 / 20%)', 0,255,0,51, ""), + # css-color-4 hsl() color function + # https://drafts.csswg.org/css-color/#the-hsl-notation + ('css-color-4-hsl-1', 'hsl(120 100.0% 50.0%)', 0,255,0,255, ""), + ('css-color-4-hsl-2', 'hsl(120 100.0% 50.0% / 0.2)', 0,255,0,51, ""), + ('css-color-4-hsl-3', 'hsl(120.0, 100.0%, 50.0%, 0.2)', 0,255,0,51, ""), + ('css-color-4-hsl-4', 'hsl(120.0, 100.0%, 50.0%, 20%)', 0,255,0,51, ""), + ('css-color-4-hsl-5', 'hsl(120deg, 100.0%, 50.0%, 0.2)', 0,255,0,51, ""), + ('css-color-4-hsl-6', 'hsl(120deg, 100.0%, 50.0%)', 0,255,0,255, ""), + ('css-color-4-hsl-7', 'hsl(133.33333333grad, 100.0%, 50.0%)', 0,255,0,255, ""), + ('css-color-4-hsl-8', 'hsl(2.0943951024rad, 100.0%, 50.0%)', 0,255,0,255, ""), + ('css-color-4-hsl-9', 'hsl(0.3333333333turn, 100.0%, 50.0%)', 0,255,0,255, ""), + ('css-color-4-hsla-1', 'hsl(120 100.0% 50.0%)', 0,255,0,255, ""), + ('css-color-4-hsla-2', 'hsl(120 100.0% 50.0% / 0.2)', 0,255,0,51, ""), + ('css-color-4-hsla-3', 'hsl(120.0, 100.0%, 50.0%, 0.2)', 0,255,0,51, ""), + ('css-color-4-hsla-4', 'hsl(120.0, 100.0%, 50.0%, 20%)', 0,255,0,51, ""), + ('css-color-4-hsla-5', 'hsl(120deg, 100.0%, 50.0%, 0.2)', 0,255,0,51, ""), + ('css-color-4-hsla-6', 'hsl(120deg, 100.0%, 50.0%)', 0,255,0,255, ""), + ('css-color-4-hsla-7', 'hsl(133.33333333grad, 100.0%, 50.0%)', 0,255,0,255, ""), + ('css-color-4-hsla-8', 'hsl(2.0943951024rad, 100.0%, 50.0%)', 0,255,0,255, ""), + ('css-color-4-hsla-9', 'hsl(0.3333333333turn, 100.0%, 50.0%)', 0,255,0,255, ""), + # currentColor is handled later + ]: + # TODO: test by retrieving fillStyle, instead of actually drawing? + # TODO: test strokeStyle, shadowColor in the same way + test = { + 'name': '2d.fillStyle.parse.%s' % name, + 'notes': notes, + 'code': """ + ctx.fillStyle = '#f00'; + ctx.fillStyle = '%s'; + ctx.fillRect(0, 0, 100, 50); + @assert pixel 50,25 == %d,%d,%d,%d; + """ % (string, r,g,b,a), + 'expected': """size 100 50 + cr.set_source_rgba(%f, %f, %f, %f) + cr.rectangle(0, 0, 100, 50) + cr.fill() + """ % (r/255., g/255., b/255., a/255.), + } + tests.append(test) + + # Also test that invalid colors are ignored + for name, string in [ + ('hex1', '#f'), + ('hex2', '#f0'), + ('hex3', '#g00'), + ('hex4', '#fg00'), + ('hex5', '#ff000'), + ('hex6', '#fg0000'), + ('hex7', '#ff0000f'), + ('hex8', '#fg0000ff'), + ('rgb-1', 'rgb(255.0, 0, 0,)'), + ('rgb-2', 'rgb(100%, 0, 0)'), + ('rgb-3', 'rgb(255, - 1, 0)'), + ('rgba-1', 'rgba(100%, 0, 0, 1)'), + ('rgba-2', 'rgba(255, 0, 0, 1. 0)'), + ('rgba-3', 'rgba(255, 0, 0, 1.)'), + ('rgba-4', 'rgba(255, 0, 0, '), + ('rgba-5', 'rgba(255, 0, 0, 1,)'), + ('hsl-1', 'hsl(0%, 100%, 50%)'), + ('hsl-2', 'hsl(z, 100%, 50%)'), + ('hsl-3', 'hsl(0, 0, 50%)'), + ('hsl-4', 'hsl(0, 100%, 0)'), + ('hsl-5', 'hsl(0, 100.%, 50%)'), + ('hsl-6', 'hsl(0, 100%, 50%,)'), + ('hsla-1', 'hsla(0%, 100%, 50%, 1)'), + ('hsla-2', 'hsla(0, 0, 50%, 1)'), + ('hsla-3', 'hsla(0, 0, 50%, 1,)'), + ('name-1', 'darkbrown'), + ('name-2', 'firebrick1'), + ('name-3', 'red blue'), + ('name-4', '"red"'), + ('name-5', '"red'), + # css-color-4 color function + # comma and comma-less expressions should not mix together. + ('css-color-4-rgb-1', 'rgb(255, 0, 0 / 1)'), + ('css-color-4-rgb-2', 'rgb(255 0 0, 1)'), + ('css-color-4-rgb-3', 'rgb(255, 0 0)'), + ('css-color-4-rgba-1', 'rgba(255, 0, 0 / 1)'), + ('css-color-4-rgba-2', 'rgba(255 0 0, 1)'), + ('css-color-4-rgba-3', 'rgba(255, 0 0)'), + ('css-color-4-hsl-1', 'hsl(0, 100%, 50% / 1)'), + ('css-color-4-hsl-2', 'hsl(0 100% 50%, 1)'), + ('css-color-4-hsl-3', 'hsl(0, 100% 50%)'), + ('css-color-4-hsla-1', 'hsla(0, 100%, 50% / 1)'), + ('css-color-4-hsla-2', 'hsla(0 100% 50%, 1)'), + ('css-color-4-hsla-3', 'hsla(0, 100% 50%)'), + # trailing slash + ('css-color-4-rgb-4', 'rgb(0 0 0 /)'), + ('css-color-4-rgb-5', 'rgb(0, 0, 0 /)'), + ('css-color-4-hsl-4', 'hsl(0 100% 50% /)'), + ('css-color-4-hsl-5', 'hsl(0, 100%, 50% /)'), + ]: + test = { + 'name': '2d.fillStyle.parse.invalid.%s' % name, + 'code': """ + ctx.fillStyle = '#0f0'; + try { ctx.fillStyle = '%s'; } catch (e) { } // this shouldn't throw, but it shouldn't matter here if it does + ctx.fillRect(0, 0, 100, 50); + @assert pixel 50,25 == 0,255,0,255; + """ % string, + 'expected': 'green' + } + tests.append(test) + + # Some can't have positive tests, only negative tests, because we don't know what color they're meant to be + for name, string in [ + ('system', 'ThreeDDarkShadow'), + #('flavor', 'flavor'), # removed from latest CSS3 Color drafts + ]: + test = { + 'name': '2d.fillStyle.parse.%s' % name, + 'code': """ + ctx.fillStyle = '#f00'; + ctx.fillStyle = '%s'; + @assert ctx.fillStyle =~ /^#(?!(FF0000|ff0000|f00)$)/; // test that it's not red + """ % (string,), + } + tests.append(test) \ No newline at end of file diff --git a/testing/web-platform/tests/html/canvas/tools/yaml/element/the-canvas-element.yaml b/testing/web-platform/tests/html/canvas/tools/yaml/element/the-canvas-element.yaml new file mode 100644 index 0000000000..1ecf8ccdbf --- /dev/null +++ b/testing/web-platform/tests/html/canvas/tools/yaml/element/the-canvas-element.yaml @@ -0,0 +1,143 @@ +- name: 2d.canvas.context.exists + desc: The 2D context is implemented + code: | + @assert canvas.getContext('2d') !== null; + +- name: 2d.canvas.context.invalid.args + desc: Calling getContext with invalid arguments. + code: | + @assert canvas.getContext('') === null; + @assert canvas.getContext('2d#') === null; + @assert canvas.getContext('This is clearly not a valid context name.') === null; + @assert canvas.getContext('2d\0') === null; + @assert canvas.getContext('2\uFF44') === null; + @assert canvas.getContext('2D') === null; + @assert throws TypeError canvas.getContext(); + @assert canvas.getContext('null') === null; + @assert canvas.getContext('undefined') === null; + +- name: 2d.canvas.context.extraargs.create + desc: The 2D context doesn't throw with extra getContext arguments (new context) + code: | + @assert document.createElement("canvas").getContext('2d', false, {}, [], 1, "2") !== null; + @assert document.createElement("canvas").getContext('2d', 123) !== null; + @assert document.createElement("canvas").getContext('2d', "test") !== null; + @assert document.createElement("canvas").getContext('2d', undefined) !== null; + @assert document.createElement("canvas").getContext('2d', null) !== null; + @assert document.createElement("canvas").getContext('2d', Symbol.hasInstance) !== null; + +- name: 2d.canvas.context.extraargs.cache + desc: The 2D context doesn't throw with extra getContext arguments (cached) + code: | + @assert canvas.getContext('2d', false, {}, [], 1, "2") !== null; + @assert canvas.getContext('2d', 123) !== null; + @assert canvas.getContext('2d', "test") !== null; + @assert canvas.getContext('2d', undefined) !== null; + @assert canvas.getContext('2d', null) !== null; + @assert canvas.getContext('2d', Symbol.hasInstance) !== null; + +- name: 2d.canvas.context.type.exists + desc: The 2D context interface is a property of 'window' + notes: &bindings Defined in "Web IDL" (draft) + code: | + @assert window.CanvasRenderingContext2D; + +- name: 2d.canvas.context.type.prototype + desc: window.CanvasRenderingContext2D.prototype are not [[Writable]] and not [[Configurable]], + and its methods are [[Configurable]]. + notes: *bindings + code: | + @assert window.CanvasRenderingContext2D.prototype; + @assert window.CanvasRenderingContext2D.prototype.fill; + window.CanvasRenderingContext2D.prototype = null; + @assert window.CanvasRenderingContext2D.prototype; + delete window.CanvasRenderingContext2D.prototype; + @assert window.CanvasRenderingContext2D.prototype; + window.CanvasRenderingContext2D.prototype.fill = 1; + @assert window.CanvasRenderingContext2D.prototype.fill === 1; + delete window.CanvasRenderingContext2D.prototype.fill; + @assert window.CanvasRenderingContext2D.prototype.fill === undefined; + +- name: 2d.canvas.context.type.replace + desc: Interface methods can be overridden + notes: *bindings + code: | + var fillRect = window.CanvasRenderingContext2D.prototype.fillRect; + window.CanvasRenderingContext2D.prototype.fillRect = function (x, y, w, h) + { + this.fillStyle = '#0f0'; + fillRect.call(this, x, y, w, h); + }; + ctx.fillStyle = '#f00'; + ctx.fillRect(0, 0, 100, 50); + @assert pixel 50,25 == 0,255,0,255; + expected: green + +- name: 2d.canvas.context.type.extend + desc: Interface methods can be added + notes: *bindings + code: | + window.CanvasRenderingContext2D.prototype.fillRectGreen = function (x, y, w, h) + { + this.fillStyle = '#0f0'; + this.fillRect(x, y, w, h); + }; + ctx.fillStyle = '#f00'; + ctx.fillRectGreen(0, 0, 100, 50); + @assert pixel 50,25 == 0,255,0,255; + expected: green + +- name: 2d.canvas.context.unique + desc: getContext('2d') returns the same object + code: | + @assert canvas.getContext('2d') === canvas.getContext('2d'); + +- name: 2d.canvas.context.shared + desc: getContext('2d') returns objects which share canvas state + code: | + var ctx2 = canvas.getContext('2d'); + ctx.fillStyle = '#f00'; + ctx2.fillStyle = '#0f0'; + ctx.fillRect(0, 0, 100, 50); + @assert pixel 50,25 == 0,255,0,255; + expected: green + +- name: 2d.canvas.host.scaled + desc: CSS-scaled canvases get drawn correctly + size: 50, 25 + canvas: 'style="width: 100px; height: 50px"' + manual: + code: | + ctx.fillStyle = '#00f'; + ctx.fillRect(0, 0, 50, 25); + ctx.fillStyle = '#0ff'; + ctx.fillRect(0, 0, 25, 10); + expected: | + size 100 50 + cr.set_source_rgb(0, 0, 1) + cr.rectangle(0, 0, 100, 50) + cr.fill() + cr.set_source_rgb(0, 1, 1) + cr.rectangle(0, 0, 50, 20) + cr.fill() + +- name: 2d.canvas.host.reference + desc: CanvasRenderingContext2D.canvas refers back to its canvas + code: | + @assert ctx.canvas === canvas; + +- name: 2d.canvas.host.readonly + desc: CanvasRenderingContext2D.canvas is readonly + code: | + var c = document.createElement('canvas'); + var d = ctx.canvas; + @assert c !== d; + ctx.canvas = c; + @assert ctx.canvas === d; + +- name: 2d.canvas.context.prototype + desc: checks CanvasRenderingContext2D prototype + code: | + @assert Object.getPrototypeOf(CanvasRenderingContext2D.prototype) === Object.prototype; + @assert Object.getPrototypeOf(ctx) === CanvasRenderingContext2D.prototype; + t.done(); -- cgit v1.2.3