From ff72283a28323e4a691acd7ae199901c6ebc9568 Mon Sep 17 00:00:00 2001 From: Blink WPT Bot Date: Fri, 3 Dec 2021 18:09:16 -0800 Subject: [PATCH] Unify template to create canvas and offscreencanvas tests (#31822) The typical way to add tests for canvas and offscreencanvas is as following: - write the test in yaml/element (create the test for canvas) - copy the the test to yaml/offscreencanvas - add t.done() to the end of test (create the test for offscreencanvas) This is because the API for canvas and offscreencanvas are mostly the same. This cl updates templates and gentestutils to allow the framework of generate canvas and offscreencanvas test from test. I removed both yaml/element/color_space.yaml and yaml/offscreencanvas/color_space.yaml and add yaml_new/color_space.yaml. Now the yaml_new/color_space.yaml generates the same results as before. Note that it's possible to add test for a particular canvas type by using canvasType as keyword. Bug: 1275750 Change-Id: I6bf48ec3081f5fe3669bf585f92b39a712045c6b Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3307080 Reviewed-by: Fernando Serboncini Reviewed-by: Juanmi Huertas Commit-Queue: Yi Xu Cr-Commit-Position: refs/heads/main@{#947713} Co-authored-by: Yi Xu --- .../2d.color.space.p3.to.p3.html | 2 +- .../2d.color.space.p3.to.srgb.html | 2 +- html/canvas/tools/gentest.py | 6 +- html/canvas/tools/gentest_union.py | 3 + html/canvas/tools/gentestutils.py | 8 +- html/canvas/tools/gentestutilsunion.py | 426 ++++++++++++++++++ html/canvas/tools/name2dir-canvas.yaml | 55 +++ html/canvas/tools/name2dir.yaml | 17 +- ...ates-offscreen.yaml => templates-new.yaml} | 36 +- html/canvas/tools/templates.yaml | 54 ++- .../element => yaml-new}/color_space.yaml | 24 +- .../tools/yaml/offscreen/color_space.yaml | 42 -- 12 files changed, 609 insertions(+), 66 deletions(-) create mode 100644 html/canvas/tools/gentest_union.py create mode 100644 html/canvas/tools/gentestutilsunion.py create mode 100644 html/canvas/tools/name2dir-canvas.yaml rename html/canvas/tools/{templates-offscreen.yaml => templates-new.yaml} (60%) rename html/canvas/tools/{yaml/element => yaml-new}/color_space.yaml (97%) delete mode 100644 html/canvas/tools/yaml/offscreen/color_space.yaml diff --git a/html/canvas/element/wide-gamut-canvas/2d.color.space.p3.to.p3.html b/html/canvas/element/wide-gamut-canvas/2d.color.space.p3.to.p3.html index 55d13a173c2dbc..063012f2826e5c 100644 --- a/html/canvas/element/wide-gamut-canvas/2d.color.space.p3.to.p3.html +++ b/html/canvas/element/wide-gamut-canvas/2d.color.space.p3.to.p3.html @@ -20,9 +20,9 @@

2d.color.space.p3.to.p3

_addTest(function(canvas, ctx) { var color_style = 'rgb(50, 100, 150)'; -var epsilon = 2; // [0.24304, 0.38818, 0.57227, 1.0] * 255 = [62, 99, 146, 255] var pixel_expected = [62, 99, 146, 255]; +var epsilon = 2; ctx.fillStyle = color_style; ctx.fillRect(0, 0, 10, 10); diff --git a/html/canvas/element/wide-gamut-canvas/2d.color.space.p3.to.srgb.html b/html/canvas/element/wide-gamut-canvas/2d.color.space.p3.to.srgb.html index adf8810554cf4c..2cbeaf3b9b0777 100644 --- a/html/canvas/element/wide-gamut-canvas/2d.color.space.p3.to.srgb.html +++ b/html/canvas/element/wide-gamut-canvas/2d.color.space.p3.to.srgb.html @@ -20,8 +20,8 @@

2d.color.space.p3.to.srgb

_addTest(function(canvas, ctx) { var color_style = 'rgb(50, 100, 150)'; -var epsilon = 2; var pixel_expected = [50, 100, 150, 255]; +var epsilon = 2; ctx.fillStyle = color_style; ctx.fillRect(0, 0, 10, 10); diff --git a/html/canvas/tools/gentest.py b/html/canvas/tools/gentest.py index 5c223e41fba054..969602cf2d0321 100644 --- a/html/canvas/tools/gentest.py +++ b/html/canvas/tools/gentest.py @@ -1,4 +1,6 @@ from gentestutils import genTestUtils +from gentestutilsunion import genTestUtils_union -genTestUtils('../element', '../element', 'templates.yaml', 'name2dir.yaml', False) -genTestUtils('../offscreen', '../offscreen', 'templates-offscreen.yaml', 'name2dir-offscreen.yaml', True) +genTestUtils('../element', '../element', 'templates.yaml', 'name2dir-canvas.yaml', False) +genTestUtils('../offscreen', '../offscreen', 'templates.yaml', 'name2dir-offscreen.yaml', True) +genTestUtils_union('templates-new.yaml', 'name2dir-canvas.yaml') \ No newline at end of file diff --git a/html/canvas/tools/gentest_union.py b/html/canvas/tools/gentest_union.py new file mode 100644 index 00000000000000..62c1cde6a1154b --- /dev/null +++ b/html/canvas/tools/gentest_union.py @@ -0,0 +1,3 @@ +from gentestutilsunion import genTestUtils_union + +genTestUtils_union('templates-new.yaml', 'name2dir-canvas.yaml') diff --git a/html/canvas/tools/gentestutils.py b/html/canvas/tools/gentestutils.py index c4c1cf720a3ceb..7fe21ee061c022 100644 --- a/html/canvas/tools/gentestutils.py +++ b/html/canvas/tools/gentestutils.py @@ -404,13 +404,15 @@ def expand_test_code(code): 'fallback':fallback, 'attributes':attributes, 'context_args': context_args } - - f = codecs.open('%s/%s%s.html' % (TESTOUTPUTDIR, mapped_name, name_variant), 'w', 'utf-8') - f.write(templates['w3c'] % template_params) if ISOFFSCREENCANVAS: + f = codecs.open('%s/%s%s.html' % (TESTOUTPUTDIR, mapped_name, name_variant), 'w', 'utf-8') + f.write(templates['w3coffscreencanvas'] % template_params) timeout = '// META: timeout=%s\n' % test['timeout'] if 'timeout' in test else '' template_params['timeout'] = timeout f = codecs.open('%s/%s%s.worker.js' % (TESTOUTPUTDIR, mapped_name, name_variant), 'w', 'utf-8') f.write(templates['w3cworker'] % template_params) + else: + f = codecs.open('%s/%s%s.html' % (TESTOUTPUTDIR, mapped_name, name_variant), 'w', 'utf-8') + f.write(templates['w3ccanvas'] % template_params) print() diff --git a/html/canvas/tools/gentestutilsunion.py b/html/canvas/tools/gentestutilsunion.py new file mode 100644 index 00000000000000..2359ef03a917cd --- /dev/null +++ b/html/canvas/tools/gentestutilsunion.py @@ -0,0 +1,426 @@ +# Current code status: +# +# This was originally written by Philip Taylor for use at +# http://philip.html5.org/tests/canvas/suite/tests/ +# +# It has been adapted for use with the Web Platform Test Suite suite at +# https://github.com/web-platform-tests/wpt/ +# +# The original version had a number of now-removed features (multiple versions of +# each test case of varying verbosity, Mozilla mochitests, semi-automated test +# harness). It also had a different directory structure. + +# To update or add test cases: +# +# * Modify the tests*.yaml files. +# 'name' is an arbitrary hierarchical name to help categorise tests. +# 'desc' is a rough description of what behaviour the test aims to test. +# 'testing' is a list of references to spec.yaml, to show which spec sentences +# this test case is primarily testing. +# 'code' is JavaScript code to execute, with some special commands starting with '@' +# 'expected' is what the final canvas output should be: a string 'green' or 'clear' +# (100x50 images in both cases), or a string 'size 100 50' (or any other size) +# followed by Python code using Pycairo to generate the image. +# +# * Run "./build.sh". +# This requires a few Python modules which might not be ubiquitous. +# It will usually emit some warnings, which ideally should be fixed but can +# generally be safely ignored. +# +# * Test the tests, add new ones to Git, remove deleted ones from Git, etc. + +from __future__ import print_function + +import re +import codecs +import time +import os +import shutil +import sys +import xml.dom.minidom +from xml.dom.minidom import Node + +try: + import cairocffi as cairo +except ImportError: + import cairo + +try: + import syck as yaml # compatible and lots faster +except ImportError: + import yaml + +def genTestUtils_union(TEMPLATEFILE, NAME2DIRFILE): + CANVASOUTPUTDIR = '../element' + CANVASIMAGEOUTPUTDIR = '../element' + OFFSCREENCANVASOUTPUTDIR = '../offscreen' + OFFSCREENCANVASIMAGEOUTPUTDIR = '../offscreen' + MISCOUTPUTDIR = './output' + SPECOUTPUTDIR = '../' + HTMLCanvas_test = True + OffscreenCanvas_test = True + + SPECOUTPUTPATH = './' # relative to CANVASOUTPUTDIR + + def simpleEscapeJS(str): + return str.replace('\\', '\\\\').replace('"', '\\"') + + def escapeJS(str): + str = simpleEscapeJS(str) + str = re.sub(r'\[(\w+)\]', r'[\\""+(\1)+"\\"]', str) # kind of an ugly hack, for nicer failure-message output + return str + + def escapeHTML(str): + return str.replace('&', '&').replace('<', '<').replace('>', '>').replace('"', '"') + + def expand_nonfinite(method, argstr, tail): + """ + >>> print expand_nonfinite('f', '<0 a>, <0 b>', ';') + f(a, 0); + f(0, b); + f(a, b); + >>> print expand_nonfinite('f', '<0 a>, <0 b c>, <0 d>', ';') + f(a, 0, 0); + f(0, b, 0); + f(0, c, 0); + f(0, 0, d); + f(a, b, 0); + f(a, b, d); + f(a, 0, d); + f(0, b, d); + """ + # argstr is ", ..." (where usually + # 'invalid' is Infinity/-Infinity/NaN) + args = [] + for arg in argstr.split(', '): + a = re.match('<(.*)>', arg).group(1) + args.append(a.split(' ')) + calls = [] + # Start with the valid argument list + call = [ args[j][0] for j in range(len(args)) ] + # For each argument alone, try setting it to all its invalid values: + for i in range(len(args)): + for a in args[i][1:]: + c2 = call[:] + c2[i] = a + calls.append(c2) + # For all combinations of >= 2 arguments, try setting them to their + # first invalid values. (Don't do all invalid values, because the + # number of combinations explodes.) + def f(c, start, depth): + for i in range(start, len(args)): + if len(args[i]) > 1: + a = args[i][1] + c2 = c[:] + c2[i] = a + if depth > 0: calls.append(c2) + f(c2, i+1, depth+1) + f(call, 0, 0) + + return '\n'.join('%s(%s)%s' % (method, ', '.join(c), tail) for c in calls) + + # Run with --test argument to run unit tests + if len(sys.argv) > 1 and sys.argv[1] == '--test': + import doctest + doctest.testmod() + sys.exit() + + templates = yaml.safe_load(open(TEMPLATEFILE, "r").read()) + name_mapping = yaml.safe_load(open(NAME2DIRFILE, "r").read()) + + SPECFILE = 'spec.yaml' + spec_assertions = [] + for s in yaml.safe_load(open(SPECFILE, "r").read())['assertions']: + if 'meta' in s: + eval(compile(s['meta'], '', 'exec'), {}, {'assertions':spec_assertions}) + else: + spec_assertions.append(s) + + tests = [] + test_yaml_directory = "yaml-new" + TESTSFILES = [ + os.path.join(test_yaml_directory, f) for f in os.listdir(test_yaml_directory) + if f.endswith(".yaml")] + for t in sum([ yaml.safe_load(open(f, "r").read()) for f in TESTSFILES], []): + if 'DISABLED' in t: + continue + if 'meta' in t: + eval(compile(t['meta'], '', 'exec'), {}, {'tests':tests}) + else: + tests.append(t) + + category_names = [] + category_contents_direct = {} + category_contents_all = {} + + spec_ids = {} + for t in spec_assertions: spec_ids[t['id']] = True + spec_refs = {} + + def backref_html(name): + backrefs = [] + c = '' + for p in name.split('.')[:-1]: + c += '.'+p + backrefs.append('%s.' % (c, p)) + backrefs.append(name.split('.')[-1]) + return ''.join(backrefs) + + # Ensure the test output directories exist + testdirs = [CANVASOUTPUTDIR, OFFSCREENCANVASOUTPUTDIR, CANVASIMAGEOUTPUTDIR, OFFSCREENCANVASIMAGEOUTPUTDIR, MISCOUTPUTDIR] + for map_dir in set(name_mapping.values()): + testdirs.append("%s/%s" % (CANVASOUTPUTDIR, map_dir)) + testdirs.append("%s/%s" % (OFFSCREENCANVASOUTPUTDIR, map_dir)) + for d in testdirs: + try: os.mkdir(d) + except: pass # ignore if it already exists + + used_images = {} + + def map_name(name): + mapped_name = None + for mn in sorted(name_mapping.keys(), key=len, reverse=True): + if name.startswith(mn): + mapped_name = "%s/%s" % (name_mapping[mn], name) + break + if not mapped_name: + print("LIKELY ERROR: %s has no defined target directory mapping" % name) + if 'manual' in test: + mapped_name += "-manual" + return mapped_name + + def expand_test_code(code, is_offscreencanvas): + code = re.sub(r'@nonfinite ([^(]+)\(([^)]+)\)(.*)', lambda m: expand_nonfinite(m.group(1), m.group(2), m.group(3)), code) # must come before '@assert throws' + + if is_offscreencanvas: + code = re.sub(r'@assert pixel (\d+,\d+) == (\d+,\d+,\d+,\d+);', + r'_assertPixel(offscreenCanvas, \1, \2, "\1", "\2");', + code) + else: + code = re.sub(r'@assert pixel (\d+,\d+) == (\d+,\d+,\d+,\d+);', + r'_assertPixel(canvas, \1, \2, "\1", "\2");', + code) + + if is_offscreencanvas: + code = re.sub(r'@assert pixel (\d+,\d+) ==~ (\d+,\d+,\d+,\d+);', + r'_assertPixelApprox(offscreenCanvas, \1, \2, "\1", "\2", 2);', + code) + else: + code = re.sub(r'@assert pixel (\d+,\d+) ==~ (\d+,\d+,\d+,\d+);', + r'_assertPixelApprox(canvas, \1, \2, "\1", "\2", 2);', + code) + + if is_offscreencanvas: + code = re.sub(r'@assert pixel (\d+,\d+) ==~ (\d+,\d+,\d+,\d+) \+/- (\d+);', + r'_assertPixelApprox(offscreenCanvas, \1, \2, "\1", "\2", \3);', + code) + else: + code = re.sub(r'@assert pixel (\d+,\d+) ==~ (\d+,\d+,\d+,\d+) \+/- (\d+);', + r'_assertPixelApprox(canvas, \1, \2, "\1", "\2", \3);', + code) + + code = re.sub(r'@assert throws (\S+_ERR) (.*);', + r'assert_throws_dom("\1", function() { \2; });', + code) + + code = re.sub(r'@assert throws (\S+Error) (.*);', + r'assert_throws_js(\1, function() { \2; });', + code) + + code = re.sub(r'@assert (.*) === (.*);', + lambda m: '_assertSame(%s, %s, "%s", "%s");' + % (m.group(1), m.group(2), escapeJS(m.group(1)), escapeJS(m.group(2))) + , code) + + code = re.sub(r'@assert (.*) !== (.*);', + lambda m: '_assertDifferent(%s, %s, "%s", "%s");' + % (m.group(1), m.group(2), escapeJS(m.group(1)), escapeJS(m.group(2))) + , code) + + code = re.sub(r'@assert (.*) =~ (.*);', + lambda m: 'assert_regexp_match(%s, %s);' + % (m.group(1), m.group(2)) + , code) + + code = re.sub(r'@assert (.*);', + lambda m: '_assert(%s, "%s");' + % (m.group(1), escapeJS(m.group(1))) + , code) + + code = re.sub(r' @moz-todo', '', code) + + code = re.sub(r'@moz-UniversalBrowserRead;', + "" + , code) + + assert('@' not in code) + + return code + + used_tests = {} + for i in range(len(tests)): + test = tests[i] + if test.get('canvasType', []): + HTMLCanvas_test = False + OffscreenCanvas_test = False + for type in test.get('canvasType'): + if type.lower() == 'htmlcanvas': + HTMLCanvas_test = True + elif type.lower() == 'offscreencanvas': + OffscreenCanvas_test = True + + name = test['name'] + print("\r(%s)" % name, " "*32, "\t") + + if name in used_tests: + print("Test %s is defined twice" % name) + used_tests[name] = 1 + + mapped_name = map_name(name) + if not mapped_name: + mapped_name = name + + + cat_total = '' + for cat_part in [''] + name.split('.')[:-1]: + cat_total += cat_part+'.' + if not cat_total in category_names: category_names.append(cat_total) + category_contents_all.setdefault(cat_total, []).append(name) + category_contents_direct.setdefault(cat_total, []).append(name) + + for ref in test.get('testing', []): + if ref not in spec_ids: + print("Test %s uses nonexistent spec point %s" % (name, ref)) + spec_refs.setdefault(ref, []).append(name) + + if not test.get('testing', []): + print("Test %s doesn't refer to any spec points" % name) + + if test.get('expected', '') == 'green' and re.search(r'@assert pixel .* 0,0,0,0;', test['code']): + print("Probable incorrect pixel test in %s" % name) + + code_canvas = expand_test_code(test['code'], False).strip() + code_offscreen = expand_test_code(test['code'], True).strip() + + expectation_html = '' + if 'expected' in test and test['expected'] is not None: + expected = test['expected'] + expected_img = None + if expected == 'green': + expected_img = "/images/green-100x50.png" + elif expected == 'clear': + expected_img = "/images/clear-100x50.png" + else: + if ';' in expected: + print("Found semicolon in %s" % name) + expected = re.sub(r'^size (\d+) (\d+)', + r'surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, \1, \2)\ncr = cairo.Context(surface)', + expected) + + if mapped_name.endswith("-manual"): + png_name = mapped_name[:-len("-manual")] + else: + png_name = mapped_name + expected_canvas = expected + "\nsurface.write_to_png('%s/%s.png')\n" % (CANVASIMAGEOUTPUTDIR, png_name) + eval(compile(expected_canvas, '' % test['name'], 'exec'), {}, {'cairo':cairo}) + + expected_offscreencanvas = expected + "\nsurface.write_to_png('%s/%s.png')\n" % (OFFSCREENCANVASIMAGEOUTPUTDIR, png_name) + eval(compile(expected_offscreencanvas, '' % test['name'], 'exec'), {}, {'cairo':cairo}) + + expected_img = "%s.png" % name + + if expected_img: + expectation_html = ('

Expected output:' + + '

' % (expected_img)) + + canvas = test.get('canvas', 'width="100" height="50"') + + prev = tests[i-1]['name'] if i != 0 else 'index' + next = tests[i+1]['name'] if i != len(tests)-1 else 'index' + + name_wrapped = name.replace('.', '.​') + + refs = ''.join('

  • %s\n' % (SPECOUTPUTPATH, n,n) for n in test.get('testing', [])) + + notes = '

    %s' % test['notes'] if 'notes' in test else '' + + timeout = '\n' % test['timeout'] if 'timeout' in test else '' + + scripts = '' + for s in test.get('scripts', []): + scripts += '\n' % (s) + + variants = test.get('script-variants', {}) + script_variants = [(v, '\n' % (s)) for (v, s) in variants.items()] + if not script_variants: + script_variants = [('', '')] + + images = '' + for i in test.get('images', []): + id = i.split('/')[-1] + if '/' not in i: + used_images[i] = 1 + i = '../images/%s' % i + images += '\n' % (i,id) + for i in test.get('svgimages', []): + id = i.split('/')[-1] + if '/' not in i: + used_images[i] = 1 + i = '../images/%s' % i + images += '\n' % (i,id) + images = images.replace("../images/", "/images/") + + fonts = '' + fonthack = '' + for i in test.get('fonts', []): + fonts += '@font-face {\n font-family: %s;\n src: url("/fonts/%s.ttf");\n}\n' % (i, i) + # Browsers require the font to actually be used in the page + if test.get('fonthack', 1): + fonthack += 'A\n' % i + if fonts: + fonts = '\n' % fonts + + fallback = test.get('fallback', '

    FAIL (fallback content)

    ') + + desc = test.get('desc', '') + escaped_desc = simpleEscapeJS(desc) + + attributes = test.get('attributes', '') + if attributes: + context_args = "'2d', %s" % attributes.strip() + attributes = ', ' + attributes.strip() + else: + context_args = "'2d'" + + for (variant, extra_script) in script_variants: + name_variant = '' if not variant else '.' + variant + + template_params = { + 'name':name + name_variant, + 'name_wrapped':name_wrapped, 'backrefs':backref_html(name), + 'mapped_name':mapped_name, + 'desc':desc, 'escaped_desc':escaped_desc, + 'prev':prev, 'next':next, 'refs':refs, 'notes':notes, 'images':images, + 'fonts':fonts, 'fonthack':fonthack, 'timeout': timeout, + 'canvas':canvas, 'expected':expectation_html, 'code':code_canvas, + 'scripts':scripts + extra_script, + 'fallback':fallback, 'attributes':attributes, + 'context_args': context_args + } + + # Create test cases for canvas and offscreencanvas. + if HTMLCanvas_test: + f = codecs.open('%s/%s%s.html' % (CANVASOUTPUTDIR, mapped_name, name_variant), 'w', 'utf-8') + f.write(templates['w3ccanvas'] % template_params) + if OffscreenCanvas_test: + template_params['code'] = code_offscreen + f = codecs.open('%s/%s%s.html' % (OFFSCREENCANVASOUTPUTDIR, mapped_name, name_variant), 'w', 'utf-8') + f.write(templates['w3coffscreencanvas'] % template_params) + + # Create test case for offscreencanvas worker. + timeout = '// META: timeout=%s\n' % test['timeout'] if 'timeout' in test else '' + template_params['timeout'] = timeout + f = codecs.open('%s/%s%s.worker.js' % (OFFSCREENCANVASOUTPUTDIR, mapped_name, name_variant), 'w', 'utf-8') + f.write(templates['w3cworker'] % template_params) + + print() diff --git a/html/canvas/tools/name2dir-canvas.yaml b/html/canvas/tools/name2dir-canvas.yaml new file mode 100644 index 00000000000000..f1ebe4b8a9d0c3 --- /dev/null +++ b/html/canvas/tools/name2dir-canvas.yaml @@ -0,0 +1,55 @@ +2d.transformation: "transformations" +2d.color.space: 'wide-gamut-canvas' +2d.composite: "compositing" +2d.coordinatespace: "conformance-requirements" +2d.missingargs: "conformance-requirements" +2d.type.delete: "conformance-requirements" +2d.voidreturn: "conformance-requirements" +2d.drawImage: "drawing-images-to-the-canvas" +2d.clearRect: "drawing-rectangles-to-the-canvas" +2d.fillRect: "drawing-rectangles-to-the-canvas" +2d.strokeRect: "drawing-rectangles-to-the-canvas" +2d.text.draw: "drawing-text-to-the-canvas" +2d.text.draw.space.basic: "drawing-text-to-the-canvas" +2d.text.draw.space.collapse: "drawing-text-to-the-canvas" +2d.text.measure: "drawing-text-to-the-canvas" +2d.fillStyle: "fill-and-stroke-styles" +2d.gradient: "fill-and-stroke-styles" +2d.pattern: "fill-and-stroke-styles" +2d.strokeStyle: "fill-and-stroke-styles" +2d.line: "line-styles" +2d.path: "path-objects" +2d.imageData: "pixel-manipulation" +2d.reset: "reset" +2d.shadow: "shadows" +2d.filter: "filters" +2d.text.align: "text-styles" +2d.text.baseline: "text-styles" +2d.text.font: "text-styles" +2d.text.draw.baseline: "text-styles" +2d.text.draw.space: "text-styles" +2d.text.measure.width.space: "text-styles" +2d.text.draw.space.collapse.end: "text-styles" +2d.text.draw.space.collapse.other: "text-styles" +2d.text.draw.space.collapse.space: "text-styles" +2d.text.draw.space.collapse.start: "text-styles" +2d.state: "the-canvas-state" +2d.scrollPathIntoView: "scroll" +2d.video: "video" +2d.canvas: "../../../html/semantics/embedded-content/the-canvas-element" +2d.getcontext: "../../../html/semantics/embedded-content/the-canvas-element" +2d.scaled: "../../../html/semantics/embedded-content/the-canvas-element" +2d.type: "../../../html/semantics/embedded-content/the-canvas-element" +context: "../../../html/semantics/embedded-content/the-canvas-element" +fallback: "../../../html/semantics/embedded-content/the-canvas-element" +initial: "../../../html/semantics/embedded-content/the-canvas-element" +security: "../../../html/semantics/embedded-content/the-canvas-element" +size: "../../../html/semantics/embedded-content/the-canvas-element" +toBlob: "../../../html/semantics/embedded-content/the-canvas-element" +toDataURL: "../../../html/semantics/embedded-content/the-canvas-element" +type: "../../../html/semantics/embedded-content/the-canvas-element" +2d.offscreencanvas: "the-offscreen-canvas" +2d.offscreencanva.getcontext: "the-offscreen-canvas" +2d.offscreencanva.context: "the-offscreen-canvas" +2d.offscreencanva.initial: "the-offscreen-canvas" +2d.offscreencanva.size: "the-offscreen-canvas" \ No newline at end of file diff --git a/html/canvas/tools/name2dir.yaml b/html/canvas/tools/name2dir.yaml index 8f3c2c9d35eb6f..e2c4d971a45ac4 100644 --- a/html/canvas/tools/name2dir.yaml +++ b/html/canvas/tools/name2dir.yaml @@ -37,14 +37,9 @@ 2d.scrollPathIntoView: "scroll" 2d.video: "video" 2d.canvas: "../../../html/semantics/embedded-content/the-canvas-element" -2d.getcontext: "../../../html/semantics/embedded-content/the-canvas-element" -2d.scaled: "../../../html/semantics/embedded-content/the-canvas-element" -2d.type: "../../../html/semantics/embedded-content/the-canvas-element" -context: "../../../html/semantics/embedded-content/the-canvas-element" -fallback: "../../../html/semantics/embedded-content/the-canvas-element" -initial: "../../../html/semantics/embedded-content/the-canvas-element" -security: "../../../html/semantics/embedded-content/the-canvas-element" -size: "../../../html/semantics/embedded-content/the-canvas-element" -toBlob: "../../../html/semantics/embedded-content/the-canvas-element" -toDataURL: "../../../html/semantics/embedded-content/the-canvas-element" -type: "../../../html/semantics/embedded-content/the-canvas-element" +2d.canvas.getcontext: "../../../html/semantics/embedded-content/the-canvas-element" +2d.canvas.scaled: "../../../html/semantics/embedded-content/the-canvas-element" +2d.canvas.type: "../../../html/semantics/embedded-content/the-canvas-element" +2d.canvas.initial: "../../../html/semantics/embedded-content/the-canvas-element" +2d.canvas.size: "../../../html/semantics/embedded-content/the-canvas-element" +2d.canvas.type: "../../../html/semantics/embedded-content/the-canvas-element" diff --git a/html/canvas/tools/templates-offscreen.yaml b/html/canvas/tools/templates-new.yaml similarity index 60% rename from html/canvas/tools/templates-offscreen.yaml rename to html/canvas/tools/templates-new.yaml index acf7535ff3dab3..ecf9e68f506bd2 100644 --- a/html/canvas/tools/templates-offscreen.yaml +++ b/html/canvas/tools/templates-new.yaml @@ -1,4 +1,4 @@ -w3c: | +w3coffscreencanvas: | OffscreenCanvas test: %(name)s%(timeout)s @@ -22,6 +22,8 @@ w3c: | var ctx = offscreenCanvas.getContext(%(context_args)s); %(code)s + t.done(); + }); @@ -46,5 +48,37 @@ w3cworker: | var ctx = offscreenCanvas.getContext(%(context_args)s); %(code)s + t.done(); + }); done(); + + +w3ccanvas: | + + + Canvas test: %(name)s + + + + + %(fonts)s + +

    %(name)s

    +

    %(desc)s

    + + %(notes)s + %(fonthack)s

    Actual output:

    + %(fallback)s + %(expected)s +
      + + %(scripts)s%(images)s diff --git a/html/canvas/tools/templates.yaml b/html/canvas/tools/templates.yaml index af0e656dd6d27e..6d6c4750c10f72 100644 --- a/html/canvas/tools/templates.yaml +++ b/html/canvas/tools/templates.yaml @@ -1,4 +1,56 @@ -w3c: | +w3coffscreencanvas: | + + + OffscreenCanvas test: %(name)s%(timeout)s + + + + +

      %(name)s

      +

      %(desc)s

      + + %(notes)s + + + +w3cworker: | + %(timeout)s// DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. + // OffscreenCanvas test in a worker:%(name)s + // Description:%(desc)s + // Note:%(notes)s + + importScripts("/resources/testharness.js"); + importScripts("/html/canvas/resources/canvas-tests.js"); + + var t = async_test("%(escaped_desc)s"); + var t_pass = t.done.bind(t); + var t_fail = t.step_func(function(reason) { + throw reason; + }); + t.step(function() { + + var offscreenCanvas = new OffscreenCanvas(100, 50); + var ctx = offscreenCanvas.getContext(%(context_args)s); + + %(code)s + }); + done(); + + +w3ccanvas: | Canvas test: %(name)s diff --git a/html/canvas/tools/yaml/element/color_space.yaml b/html/canvas/tools/yaml-new/color_space.yaml similarity index 97% rename from html/canvas/tools/yaml/element/color_space.yaml rename to html/canvas/tools/yaml-new/color_space.yaml index 2709f95017369d..cce1ff8ca4ba7b 100644 --- a/html/canvas/tools/yaml/element/color_space.yaml +++ b/html/canvas/tools/yaml-new/color_space.yaml @@ -1,14 +1,14 @@ - name: 2d.color.space.p3.to.p3 testing: - - 2d.color.space.p3.and.uint8 + - 2d.color.space.p3.to.p3 desc: test getImageData with display-p3 and uint8 from display p3 uint8 canvas attributes: | {colorSpace: "display-p3"} code: | var color_style = 'rgb(50, 100, 150)'; - var epsilon = 2; // [0.24304, 0.38818, 0.57227, 1.0] * 255 = [62, 99, 146, 255] var pixel_expected = [62, 99, 146, 255]; + var epsilon = 2; ctx.fillStyle = color_style; ctx.fillRect(0, 0, 10, 10); @@ -21,14 +21,14 @@ - name: 2d.color.space.p3.to.srgb testing: - - 2d.color.space.p3.and.uint8 + - 2d.color.space.p3.to.srgb desc: test getImageData with srsb and uint8 from display p3 uint8 canvas attributes: | {colorSpace: "display-p3"} code: | var color_style = 'rgb(50, 100, 150)'; - var epsilon = 2; var pixel_expected = [50, 100, 150, 255]; + var epsilon = 2; ctx.fillStyle = color_style; ctx.fillRect(0, 0, 10, 10); @@ -45,6 +45,8 @@ desc: test if toblob returns p3 data from p3 color space canvas attributes: | {colorSpace: "display-p3"} + canvasType: + ['HTMLCanvas'] code: | ctx.fillStyle = "rgba(155, 27, 27, 1)"; ctx.fillRect(0, 0, 1, 1); @@ -78,6 +80,8 @@ desc: test if toDataURL returns p3 data from canvas with p3 color space attributes: | {colorSpace: "display-p3"} + canvasType: + ['HTMLCanvas'] code: | ctx.fillStyle = "rgba(155, 27, 27, 1)"; ctx.fillRect(0, 0, 1, 1); @@ -107,6 +111,8 @@ desc: test if toDataURL('image/jpeg') returns p3 data from canvas with p3 color space attributes: | {colorSpace: "display-p3"} + canvasType: + ['HTMLCanvas'] code: | ctx.fillStyle = "rgba(155, 27, 27, 1)"; ctx.fillRect(0, 0, 1, 1); @@ -136,6 +142,8 @@ desc: Use putImageData to put some p3 data in canvas and test if toBlob returns the same data attributes: | {colorSpace: "display-p3"} + canvasType: + ['HTMLCanvas'] code: | canvas.width = 2; canvas.height = 2; @@ -175,6 +183,8 @@ desc: Use putImageData to put some p3 data in canvas and test if toDataURL returns the same data attributes: | {colorSpace: "display-p3"} + canvasType: + ['HTMLCanvas'] code: | canvas.width = 2; canvas.height = 2; @@ -211,6 +221,8 @@ desc: Test if fillText can be used with a solid display-p3 color attributes: | {colorSpace: "display-p3"} + canvasType: + ['HTMLCanvas'] code: | deferTest(); @@ -252,6 +264,8 @@ desc: Test if strokeText can be used with a solid display-p3 color attributes: | {colorSpace: "display-p3"} + canvasType: + ['HTMLCanvas'] code: | deferTest(); @@ -294,6 +308,8 @@ desc: Test if fillText can be used with a display-p3 shadow color attributes: | {colorSpace: "display-p3"} + canvasType: + ['HTMLCanvas'] code: | deferTest(); diff --git a/html/canvas/tools/yaml/offscreen/color_space.yaml b/html/canvas/tools/yaml/offscreen/color_space.yaml deleted file mode 100644 index 0a1c4474fb49a4..00000000000000 --- a/html/canvas/tools/yaml/offscreen/color_space.yaml +++ /dev/null @@ -1,42 +0,0 @@ -- name: 2d.color.space.p3.to.p3 - testing: - - 2d.color.space.p3.to.p3 - desc: test getImageData with display-p3 and uint8 from display p3 uint8 canvas - attributes: | - {colorSpace: "display-p3"} - code: | - var color_style = 'rgb(50, 100, 150)'; - // [0.24304, 0.38818, 0.57227, 1.0] * 255 = [62, 99, 146, 255] - var pixel_expected = [62, 99, 146, 255]; - var epsilon = 2; - ctx.fillStyle = color_style; - ctx.fillRect(0, 0, 10, 10); - - var pixel = ctx.getImageData(5, 5, 1, 1, {colorSpace: "display-p3", storageFormat: "uint8"}).data; - @assert pixel.length === pixel_expected.length; - assert_approx_equals(pixel[0], pixel_expected[0], 2); - assert_approx_equals(pixel[1], pixel_expected[1], 2); - assert_approx_equals(pixel[2], pixel_expected[2], 2); - assert_approx_equals(pixel[3], pixel_expected[3], 2); - t.done(); - -- name: 2d.color.space.p3.to.srgb - testing: - - 2d.color.space.p3.to.srgb - desc: test getImageData with srsb and uint8 from display p3 uint8 canvas - attributes: | - {colorSpace: "display-p3"} - code: | - var color_style = 'rgb(50, 100, 150)'; - var pixel_expected = [50, 100, 150, 255]; - var epsilon = 2; - ctx.fillStyle = color_style; - ctx.fillRect(0, 0, 10, 10); - - var pixel = ctx.getImageData(5, 5, 1, 1, {colorSpace: "srgb", storageFormat: "uint8"}).data; - @assert pixel.length === pixel_expected.length; - assert_approx_equals(pixel[0], pixel_expected[0], 2); - assert_approx_equals(pixel[1], pixel_expected[1], 2); - assert_approx_equals(pixel[2], pixel_expected[2], 2); - assert_approx_equals(pixel[3], pixel_expected[3], 2); - t.done();