diff options
Diffstat (limited to 'testing/web-platform/tests/html/canvas/tools')
15 files changed, 788 insertions, 240 deletions
diff --git a/testing/web-platform/tests/html/canvas/tools/gentestutilsunion.py b/testing/web-platform/tests/html/canvas/tools/gentestutilsunion.py index 57077f6057..415090a14a 100644 --- a/testing/web-platform/tests/html/canvas/tools/gentestutilsunion.py +++ b/testing/web-platform/tests/html/canvas/tools/gentestutilsunion.py @@ -345,17 +345,43 @@ class _Variant(): 'desc': '', 'size': [100, 50], 'variant_names': [], + 'grid_variant_names': [], + 'images': [], + 'svgimages': [], } params.update(test) return _Variant(params) - def _get_variant_name(self, jinja_env: jinja2.Environment) -> str: - name = self.params['name'] + def merge_params(self, params: _TestParams) -> '_Variant': + """Returns a new `_Variant` that merges `self.params` and `params`.""" + new_params = {} + new_params.update(self.params) + new_params.update(params) + return _Variant(new_params) + + def with_grid_variant_name(self, name: str) -> '_Variant': + """Addend a variant name to include in the grid element label.""" + self._params.update({ + 'variant_names': (self.params['variant_names'] + [name]), + 'grid_variant_names': (self.params['grid_variant_names'] + [name]), + }) + return self + + def with_file_variant_name(self, name: str) -> '_Variant': + """Addend a variant name to include in the generated file name.""" + self._params.update({ + 'variant_names': (self.params['variant_names'] + [name]), + }) if self.params.get('append_variants_to_name', True): - name = '.'.join([name] + self.params['variant_names']) + self._params['name'] = self.params['name'] + '.' + name + return self + + def _render_param(self, jinja_env: jinja2.Environment, + param_name: str) -> str: + """Get the specified variant parameter and render it with Jinja.""" + value = self.params[param_name] + return jinja_env.from_string(value).render(self.params) - name = jinja_env.from_string(name).render(self.params) - return name def _get_file_name(self) -> str: file_name = self.params['name'] @@ -389,9 +415,12 @@ class _Variant(): return _TemplateType.HTML_REFERENCE return _TemplateType.TESTHARNESS - def finalize_params(self, jinja_env: jinja2.Environment) -> None: + def finalize_params(self, jinja_env: jinja2.Environment, + variant_id: int) -> None: """Finalize this variant by adding computed param fields.""" - self._params['name'] = self._get_variant_name(jinja_env) + self._params['id'] = variant_id + self._params['name'] = self._render_param(jinja_env, 'name') + self._params['desc'] = self._render_param(jinja_env, 'desc') self._params['file_name'] = self._get_file_name() self._params['canvas_types'] = self._get_canvas_types() self._params['template_type'] = self._get_template_type() @@ -461,103 +490,282 @@ class _Variant(): self._params['expected_img'] = f'{name}.png' + +class _VariantGrid: + + def __init__(self, variants: List[_Variant], grid_width: int) -> None: + self._variants = variants + self._grid_width = grid_width + + self._file_name = None + self._canvas_types = None + self._template_type = None + self._params = None + + @property + def variants(self) -> List[_Variant]: + """Read only getter for the list of variant in this grid.""" + return self._variants + + @property + def file_name(self): + """File name to which this grid will be written.""" + if self._file_name is None: + self._file_name = self._unique_param('file_name') + return self._file_name + + @property + def canvas_types(self) -> FrozenSet[_CanvasType]: + """Returns the set of all _CanvasType used by this grid's variants.""" + if self._canvas_types is None: + self._canvas_types = self._param_set('canvas_types') + return self._canvas_types + + @property + def template_type(self) -> _TemplateType: + """Returns the type of Jinja template needed to render this grid.""" + if self._template_type is None: + self._template_type = self._unique_param('template_type') + return self._template_type + + @property + def params(self) -> _TestParams: + """Returns this grid's param dict, used to render Jinja templates.""" + if self._params is None: + if len(self.variants) == 1: + self._params = dict(self.variants[0].params) + else: + self._params = self._get_grid_params() + return self._params + + def finalize(self, jinja_env: jinja2.Environment): + """Finalize this grid's variants, adding computed params fields.""" + for variant_id, variant in enumerate(self.variants): + variant.finalize_params(jinja_env, variant_id) + + def add_dimension(self, variants: Mapping[str, + _TestParams]) -> '_VariantGrid': + """Adds a variant dimension to this variant grid. + + If the grid currently has N variants, adding a dimension with M variants + results in a grid containing N*M variants. Of course, we can't display + more than 2 dimensions on a 2D screen, so adding dimensions beyond 2 + repeats all previous dimensions down vertically, with the grid width + set to the number of variants of the first dimension (unless overridden + by setting `grid_width`). For instance, a 3D variant space with + dimensions 3 x 2 x 2 will result in this layout: + 000 100 200 + 010 110 210 + + 001 101 201 + 011 111 211 + """ + new_variants = [ + old_variant.merge_params(params or {}).with_grid_variant_name(name) + for name, params in variants.items() + for old_variant in self.variants + ] + # The first dimension dictates the grid-width, unless it was specified + # beforehand via the test params. + new_grid_width = (self._grid_width + if self._grid_width > 1 else len(variants)) + return _VariantGrid(variants=new_variants, grid_width=new_grid_width) + + def merge_params(self, name: str, params: _TestParams) -> '_VariantGrid': + """Merges the specified `params` into every variant of this grid.""" + return _VariantGrid(variants=[ + variant.merge_params(params).with_file_variant_name(name) + for variant in self.variants + ], + grid_width=self._grid_width) + + def _variants_for_canvas_type( + self, canvas_type: _CanvasType) -> List[_TestParams]: + """Returns the variants of this grid enabled for `canvas_type`.""" + return [ + v.params for v in self.variants + if canvas_type in v.params['canvas_types'] + ] + + def _unique_param(self, name: str) -> Any: + """Returns the value of the `name` param for this grid. + + All the variants in this grid must agree on the same value for this + parameter, or else an exception is thrown.""" + values = {variant.params.get(name) for variant in self.variants} + if len(values) != 1: + raise InvalidTestDefinitionError( + 'All variants in a variant grid must use the same value ' + f'for property "{name}". Got these values: {values}. ' + 'Consider specifying the property outside of grid ' + 'variants dimensions (in the base test definition or in a ' + 'file variant dimension)') + return values.pop() + + def _param_set(self, name: str): + """Returns the set of all values this grid has for the `name` param. + + The `name` parameter of each variant is expected to be a sequence. + These are all accumulated in a set and returned.""" + return frozenset(sum([list(v.params[name]) for v in self.variants], + [])) + + def _get_grid_params(self) -> _TestParams: + """Returns the params dict needed to render this grid with Jinja.""" + filter_variant = self._variants_for_canvas_type + grid_params = { + 'element_variants': filter_variant(_CanvasType.HTML_CANVAS), + 'offscreen_variants': filter_variant(_CanvasType.OFFSCREEN_CANVAS), + 'worker_variants': filter_variant(_CanvasType.WORKER), + 'grid_width': self._grid_width, + 'name': self._unique_param('name'), + 'test_type': self._unique_param('test_type'), + 'fuzzy': self._unique_param('fuzzy'), + 'timeout': self._unique_param('timeout'), + 'notes': self._unique_param('notes'), + 'images': self._param_set('images'), + 'svgimages': self._param_set('svgimages'), + } + if self.template_type in (_TemplateType.REFERENCE, + _TemplateType.HTML_REFERENCE): + grid_params['desc'] = self._unique_param('desc') + return grid_params + def _write_reference_test(self, jinja_env: jinja2.Environment, output_files: _OutputPaths): + grid = '_grid' if len(self.variants) > 1 else '' + + # If variants don't all use the same offscreen and worker canvas types, + # the offscreen and worker grids won't be identical. The worker test + # therefore can't reuse the offscreen reference file. + offscreen_types = {_CanvasType.OFFSCREEN_CANVAS, _CanvasType.WORKER} + needs_worker_reference = len({ + variant.params['canvas_types'] & offscreen_types + for variant in self.variants + }) != 1 + params = dict(self.params) - if _CanvasType.HTML_CANVAS in params['canvas_types']: - _render(jinja_env, 'reftest_element.html', params, + params['reference_file'] = f'{params["name"]}-expected.html' + if _CanvasType.HTML_CANVAS in self.canvas_types: + _render(jinja_env, f'reftest_element{grid}.html', params, f'{output_files.element}.html') - if _CanvasType.OFFSCREEN_CANVAS in params['canvas_types']: - _render(jinja_env, 'reftest_offscreen.html', params, + if _CanvasType.OFFSCREEN_CANVAS in self.canvas_types: + _render(jinja_env, f'reftest_offscreen{grid}.html', params, f'{output_files.offscreen}.html') - if _CanvasType.WORKER in params['canvas_types']: - _render(jinja_env, 'reftest_worker.html', params, + if _CanvasType.WORKER in self.canvas_types: + if needs_worker_reference: + params['reference_file'] = f'{params["name"]}.w-expected.html' + _render(jinja_env, f'reftest_worker{grid}.html', params, f'{output_files.offscreen}.w.html') params['is_test_reference'] = True - is_html_ref = params['template_type'] == _TemplateType.HTML_REFERENCE - ref_template = 'reftest.html' if is_html_ref else 'reftest_element.html' - if _CanvasType.HTML_CANVAS in params['canvas_types']: - _render(jinja_env, ref_template, params, + is_html_ref = self.template_type == _TemplateType.HTML_REFERENCE + ref_template_name = (f'reftest{grid}.html' + if is_html_ref else f'reftest_element{grid}.html') + + if _CanvasType.HTML_CANVAS in self.canvas_types: + _render(jinja_env, ref_template_name, params, f'{output_files.element}-expected.html') - if {_CanvasType.OFFSCREEN_CANVAS, _CanvasType.WORKER - } & params['canvas_types']: - _render(jinja_env, ref_template, params, + + if self.canvas_types & offscreen_types: + # We use the same template for all reference files, so we need to + # assign the variant definition to the variable expected by the + # template. + params['element_variants'] = params.get('offscreen_variants') + _render(jinja_env, ref_template_name, params, f'{output_files.offscreen}-expected.html') + if needs_worker_reference: + params['element_variants'] = params.get('worker_variants') + _render(jinja_env, ref_template_name, params, + f'{output_files.offscreen}.w-expected.html') def _write_testharness_test(self, jinja_env: jinja2.Environment, output_files: _OutputPaths): + grid = '_grid' if len(self.variants) > 1 else '' + # Create test cases for canvas and offscreencanvas. - if _CanvasType.HTML_CANVAS in self.params['canvas_types']: - _render(jinja_env, 'testharness_element.html', self.params, + if _CanvasType.HTML_CANVAS in self.canvas_types: + _render(jinja_env, f'testharness_element{grid}.html', self.params, f'{output_files.element}.html') - - if _CanvasType.OFFSCREEN_CANVAS in self.params['canvas_types']: - _render(jinja_env, 'testharness_offscreen.html', self.params, - f'{output_files.offscreen}.html') - - if _CanvasType.WORKER in self.params['canvas_types']: - _render(jinja_env, 'testharness_worker.js', self.params, + if _CanvasType.OFFSCREEN_CANVAS in self.canvas_types: + _render(jinja_env, f'testharness_offscreen{grid}.html', + self.params, f'{output_files.offscreen}.html') + if _CanvasType.WORKER in self.canvas_types: + _render(jinja_env, f'testharness_worker{grid}.js', self.params, f'{output_files.offscreen}.worker.js') def generate_test(self, jinja_env: jinja2.Environment, output_dirs: _OutputPaths) -> None: """Generate the test files to the specified output dirs.""" - output_files = output_dirs.sub_path(self.params['file_name']) + output_files = output_dirs.sub_path(self.file_name) - if self.params['template_type'] in (_TemplateType.REFERENCE, - _TemplateType.HTML_REFERENCE): + if self.template_type in (_TemplateType.REFERENCE, + _TemplateType.HTML_REFERENCE): self._write_reference_test(jinja_env, output_files) else: self._write_testharness_test(jinja_env, output_files) -def _recursive_expand_variant_matrix(original_test: _TestParams, - variant_matrix: List[_TestParams], - current_selection: List[Tuple[str, Any]], - test_variants: List[_Variant]): - if len(current_selection) == len(variant_matrix): - # Selection for each variant is done, so add a new test to test_list. - test = dict(original_test) - variant_name_list = [] - for variant_name, variant_params in current_selection: - test.update(variant_params) - variant_name_list.append(variant_name) - # Expose variant names as a list so they can be used from the yaml - # files, which helps with better naming of tests. - test.update({'variant_names': variant_name_list}) - test_variants.append(_Variant.create_with_defaults(test)) - else: - # Continue the recursion with each possible selection for the current - # variant. - variant = variant_matrix[len(current_selection)] - for variant_options in variant.items(): - current_selection.append(variant_options) - _recursive_expand_variant_matrix(original_test, variant_matrix, - current_selection, test_variants) - current_selection.pop() - - -def _get_variants(test: _TestParams) -> List[_Variant]: - current_selection = [] - test_variants = [] - variants = test.get('variants', []) +class _VariantLayout(str, enum.Enum): + SINGLE_FILE = 'single_file' + MULTI_FILES = 'multi_files' + + +@dataclasses.dataclass +class _VariantDimension: + variants: Mapping[str, _TestParams] + layout: _VariantLayout + + +def _get_variant_dimensions(params: _TestParams) -> List[_VariantDimension]: + variants = params.get('variants', []) if not isinstance(variants, list): raise InvalidTestDefinitionError( textwrap.dedent(""" Variants must be specified as a list of variant dimensions, e.g.: - variants: - - dimension1-variant1: - param: ... - dimension1-variant2: - param: ... - - dimension2-variant1: - param: ... - dimension2-variant2: - param: ...""")) - _recursive_expand_variant_matrix(test, variants, current_selection, - test_variants) - return test_variants + variants: + - dimension1-variant1: + param: ... + dimension1-variant2: + param: ... + - dimension2-variant1: + param: ... + dimension2-variant2: + param: ...""")) + + variants_layout = params.get('variants_layout', + [_VariantLayout.MULTI_FILES] * len(variants)) + if len(variants) != len(variants_layout): + raise InvalidTestDefinitionError( + 'variants and variants_layout must be lists of the same size') + invalid_layouts = [ + l for l in variants_layout if l not in list(_VariantLayout) + ] + if invalid_layouts: + raise InvalidTestDefinitionError('Invalid variants_layout: ' + + ', '.join(invalid_layouts) + + '. Valid layouts are: ' + + ', '.join(_VariantLayout)) + + return [ + _VariantDimension(z[0], z[1]) for z in zip(variants, variants_layout) + ] + + +def _get_variant_grids(test: Mapping[str, Any]) -> List[_VariantGrid]: + base_variant = _Variant.create_with_defaults(test) + grid_width = base_variant.params.get('grid_width', 1) + grids = [_VariantGrid([base_variant], grid_width=grid_width)] + for dimension in _get_variant_dimensions(test): + variants = dimension.variants + if dimension.layout == _VariantLayout.MULTI_FILES: + grids = [ + grid.merge_params(name, params) + for name, params in variants.items() for grid in grids + ] + else: + grids = [grid.add_dimension(variants) for grid in grids] + return grids def _check_uniqueness(tested: DefaultDict[str, Set[_CanvasType]], name: str, @@ -619,21 +827,30 @@ def generate_test_files(name_to_dir_file: str) -> None: except FileExistsError: pass # Ignore if it already exists, - used_tests = collections.defaultdict(set) + used_filenames = collections.defaultdict(set) + used_variants = collections.defaultdict(set) for test in tests: print(test['name']) - for variant in _get_variants(test): - variant.finalize_params(jinja_env) - if test['name'] != variant.params['name']: - print(f' {variant.params["name"]}') + for grid in _get_variant_grids(test): + + grid.finalize(jinja_env) + if test['name'] != grid.file_name: + print(f' {grid.file_name}') - sub_dir = _get_test_sub_dir(variant.params['file_name'], - name_to_sub_dir) + sub_dir = _get_test_sub_dir(grid.file_name, name_to_sub_dir) output_sub_dirs = output_dirs.sub_path(sub_dir) - _check_uniqueness(used_tests, variant.params['name'], - variant.params['canvas_types']) - variant.generate_expected_image(output_sub_dirs) - variant.generate_test(jinja_env, output_sub_dirs) + _check_uniqueness(used_filenames, grid.file_name, + grid.canvas_types) + for variant in grid.variants: + _check_uniqueness( + used_variants, + '.'.join([grid.file_name] + + variant.params['grid_variant_names']), + grid.canvas_types) + + for variant in grid.variants: + variant.generate_expected_image(output_sub_dirs) + grid.generate_test(jinja_env, output_sub_dirs) print() diff --git a/testing/web-platform/tests/html/canvas/tools/templates/reftest_element.html b/testing/web-platform/tests/html/canvas/tools/templates/reftest_element.html index 6f7a8c8507..8f403f84f2 100644 --- a/testing/web-platform/tests/html/canvas/tools/templates/reftest_element.html +++ b/testing/web-platform/tests/html/canvas/tools/templates/reftest_element.html @@ -3,7 +3,7 @@ {% if test_type == 'promise' %}<html class="reftest-wait"> {% endif %} {% if not is_test_reference %} -<link rel="match" href="{{ name }}-expected.html"> +<link rel="match" href="{{ reference_file }}"> {% if fuzzy %}<meta name=fuzzy content="{{ fuzzy }}"> {% endif %} {% endif %} diff --git a/testing/web-platform/tests/html/canvas/tools/templates/reftest_element_grid.html b/testing/web-platform/tests/html/canvas/tools/templates/reftest_element_grid.html new file mode 100644 index 0000000000..d1c90bd993 --- /dev/null +++ b/testing/web-platform/tests/html/canvas/tools/templates/reftest_element_grid.html @@ -0,0 +1,56 @@ +<!DOCTYPE html> +<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. --> +{% if test_type == 'promise' %}<html class="reftest-wait"> +<script>pending_tests = {{ element_variants | length }};</script> +{% endif %} +{% if not is_test_reference %} +<link rel="match" href="{{ reference_file }}"> +{% if fuzzy %}<meta name=fuzzy content="{{ fuzzy }}"> +{% endif %} +{% endif %} +{% if timeout %}<meta name="timeout" content="{{ timeout }}"> +{% endif %} +<title>Canvas test: {{ name }}</title> +<h1 style="font-size: 20px;">{{ name }}</h1> +<p class="desc">{{ desc }}</p> +{% if notes %}<p class="notes">{{ notes }}{% endif %} +{% for image in images %} +<img src="/images/{{ image }}" id="{{ image }}" class="resource"> +{% endfor -%} +{% for svgimage in svgimages %} +<svg><image xlink:href="/images/{{ svgimage }}" id="{{ svgimage + }}" class="resource"></svg> +{% endfor %} + +<div style="display: grid; grid-gap: 4px; + grid-template-columns: repeat({{ grid_width }}, max-content); + font-size: 13px; text-align: center;"> +{% for variant in element_variants %} +<span> + {% for variant_name in variant.grid_variant_names %} + <div>{{ variant_name }}</div> + {% endfor %} + <canvas id="canvas{{ variant.id + }}" width="{{ variant.size[0] + }}" height="{{ variant.size[1] + }}" style="outline: 1px solid"{{ variant.canvas }}> + <p class="fallback">FAIL (fallback content)</p> + </canvas> + <script type="module"> + const canvas = document.getElementById("canvas{{ variant.id }}"); + const ctx = canvas.getContext('2d'{% + if variant.attributes %}, {{ variant.attributes }}{% endif %}); + + {{ variant.reference | trim | indent(4) if is_test_reference else + variant.code_element | trim | indent(4) }} + {% if test_type == 'promise' %} + if (--pending_tests == 0) { + document.documentElement.classList.remove("reftest-wait"); + } + {% endif %} + </script> +</span> + +{% endfor %} +</div> +{% if test_type == 'promise' %}</html>{% endif %} diff --git a/testing/web-platform/tests/html/canvas/tools/templates/reftest_grid.html b/testing/web-platform/tests/html/canvas/tools/templates/reftest_grid.html new file mode 100644 index 0000000000..9fd42b7aa5 --- /dev/null +++ b/testing/web-platform/tests/html/canvas/tools/templates/reftest_grid.html @@ -0,0 +1,30 @@ +<!DOCTYPE html> +<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. --> +<title>Canvas test: {{ name }}</title> +<h1 style="font-size: 20px;">{{ name }}</h1> +<p class="desc">{{ desc }}</p> +{% if notes %}<p class="notes">{{ notes }}{% endif %} +{% for image in images %} +<img src="/images/{{ image }}" id="{{ image }}" class="resource"> +{% endfor %} +{% for svgimage in svgimages %} +<svg><image xlink:href="/images/{{ svgimage + }}" id="{{ svgimage }}" class="resource"></svg> +{% endfor %} + +<div style="display: grid; grid-gap: 4px; + grid-template-columns: repeat({{ grid_width }}, max-content); + font-size: 13px; text-align: center;"> +{% for variant in element_variants %} +<span> + {% for variant_name in variant.grid_variant_names %} + <div>{{ variant_name }}</div> + {% endfor %} + <div style="width: {{ variant.size[0] }}px; height: {{ variant.size[1] + }}px; outline: 1px solid"> + {{ variant.html_reference | trim | indent(4) }} + </div> +</span> + +{% endfor %} +</div> diff --git a/testing/web-platform/tests/html/canvas/tools/templates/reftest_offscreen.html b/testing/web-platform/tests/html/canvas/tools/templates/reftest_offscreen.html index abc840159f..2cd8e9750d 100644 --- a/testing/web-platform/tests/html/canvas/tools/templates/reftest_offscreen.html +++ b/testing/web-platform/tests/html/canvas/tools/templates/reftest_offscreen.html @@ -2,7 +2,7 @@ <!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. --> {% if test_type == 'promise' %}<html class="reftest-wait"> {% endif %} -<link rel="match" href="{{ name }}-expected.html"> +<link rel="match" href="{{ reference_file }}"> {% if fuzzy %}<meta name=fuzzy content="{{ fuzzy }}"> {% endif %} {% if timeout %}<meta name="timeout" content="{{ timeout }}"> diff --git a/testing/web-platform/tests/html/canvas/tools/templates/reftest_offscreen_grid.html b/testing/web-platform/tests/html/canvas/tools/templates/reftest_offscreen_grid.html new file mode 100644 index 0000000000..d001260bea --- /dev/null +++ b/testing/web-platform/tests/html/canvas/tools/templates/reftest_offscreen_grid.html @@ -0,0 +1,52 @@ +<!DOCTYPE html> +<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. --> +{% if test_type == 'promise' %}<html class="reftest-wait"> +<script>pending_tests = {{ offscreen_variants | length }};</script> +{% endif %} +<link rel="match" href="{{ reference_file }}"> +{% if fuzzy %}<meta name=fuzzy content="{{ fuzzy }}"> +{% endif %} +{% if timeout %}<meta name="timeout" content="{{ timeout }}"> +{% endif %} +<title>Canvas test: {{ name }}</title> +<h1 style="font-size: 20px;">{{ name }}</h1> +<p class="desc">{{ desc }}</p> +{% if notes %}<p class="notes">{{ notes }}{% endif %} + +<div style="display: grid; grid-gap: 4px; + grid-template-columns: repeat({{ grid_width }}, max-content); + font-size: 13px; text-align: center;"> +{% for variant in offscreen_variants %} +<span> + {% for variant_name in variant.grid_variant_names %} + <div>{{ variant_name }}</div> + {% endfor %} + <canvas id="canvas{{ variant.id + }}" width="{{ variant.size[0] + }}" height="{{ variant.size[1] + }}" style="outline: 1px solid"{{ variant.canvas }}> + <p class="fallback">FAIL (fallback content)</p> + </canvas> + <script type="module"> + const canvas = new OffscreenCanvas({{ variant.size[0] }}, {{ + variant.size[1] }}); + const ctx = canvas.getContext('2d'{% + if variant.attributes %}, {{ variant.attributes }}{% endif %}); + + {{ variant.code_offscreen | trim | indent(4) }} + + const outputCanvas = document.getElementById("canvas{{ variant.id }}"); + const outputCtx = outputCanvas.getContext('2d'{% + if variant.attributes %}, {{ variant.attributes }}{% endif %}); + outputCtx.drawImage(canvas, 0, 0); +{% if test_type == 'promise' %} + if (--pending_tests == 0) { + document.documentElement.classList.remove("reftest-wait"); + } +{% endif %} + </script> +</span> + +{% endfor %} +</div> +{% if test_type == 'promise' %}</html>{% endif %} diff --git a/testing/web-platform/tests/html/canvas/tools/templates/reftest_worker.html b/testing/web-platform/tests/html/canvas/tools/templates/reftest_worker.html index 02281af5d1..50aa29d00d 100644 --- a/testing/web-platform/tests/html/canvas/tools/templates/reftest_worker.html +++ b/testing/web-platform/tests/html/canvas/tools/templates/reftest_worker.html @@ -1,7 +1,7 @@ <!DOCTYPE html> <!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. --> <html class="reftest-wait"> -<link rel="match" href="{{ name }}-expected.html"> +<link rel="match" href="{{ reference_file }}"> {% if fuzzy %}<meta name=fuzzy content="{{ fuzzy }}"> {% endif %} {% if timeout %}<meta name="timeout" content="{{ timeout }}"> diff --git a/testing/web-platform/tests/html/canvas/tools/templates/reftest_worker_grid.html b/testing/web-platform/tests/html/canvas/tools/templates/reftest_worker_grid.html new file mode 100644 index 0000000000..652dddffd8 --- /dev/null +++ b/testing/web-platform/tests/html/canvas/tools/templates/reftest_worker_grid.html @@ -0,0 +1,62 @@ +<!DOCTYPE html> +<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. --> +<html class="reftest-wait"> +<link rel="match" href="{{ reference_file }}"> +{% if fuzzy %}<meta name=fuzzy content="{{ fuzzy }}"> +{% endif %} +{% if timeout %}<meta name="timeout" content="{{ timeout }}"> +{% endif %} +<title>Canvas test: {{ name }}</title> +<h1 style="font-size: 20px;">{{ name }}</h1> +<p class="desc">{{ desc }}</p> +{% if notes %}<p class="notes">{{ notes }}{% endif %} +<script>pending_tests = {{ worker_variants | length }};</script> + +<div style="display: grid; grid-gap: 4px; + grid-template-columns: repeat({{ grid_width }}, max-content); + font-size: 13px; text-align: center;"> +{% for variant in worker_variants %} +<span> + {% for variant_name in variant.grid_variant_names %} + <div>{{ variant_name }}</div> + {% endfor %} + <canvas id="canvas{{ variant.id + }}" width="{{ variant.size[0] + }}" height="{{ variant.size[1] + }}" style="outline: 1px solid"{{ variant.canvas }}> + <p class="fallback">FAIL (fallback content)</p> + </canvas> + <script id="myWorker{{ variant.id }}" type="text/worker"> + {% set async = 'async ' if test_type == 'promise' else '' %} + self.onmessage = {{async}}function(e) { + const canvas = new OffscreenCanvas({{ + variant.size[0] }}, {{ variant.size[1] }}); + const ctx = canvas.getContext('2d'{% + if variant.attributes %}, {{ variant.attributes }}{% endif %}); + + {{ variant.code_worker | trim | indent(6) }} + + const bitmap = canvas.transferToImageBitmap(); + self.postMessage(bitmap, bitmap); + }; + </script> + <script type="module"> + const blob = new Blob([document.getElementById('myWorker{{ + variant.id }}').textContent]); + const worker = new Worker(URL.createObjectURL(blob)); + worker.addEventListener('message', msg => { + const outputCanvas = document.getElementById('canvas{{ variant.id }}'); + const outputCtx = outputCanvas.getContext('2d'{% + if variant.attributes %}, {{ variant.attributes }}{% endif %}); + outputCtx.drawImage(msg.data, 0, 0); + if (--pending_tests == 0) { + document.documentElement.classList.remove('reftest-wait'); + } + }); + worker.postMessage(null); + </script> +</span> + +{% endfor %} +</div> +</html> diff --git a/testing/web-platform/tests/html/canvas/tools/templates/testharness_element_grid.html b/testing/web-platform/tests/html/canvas/tools/templates/testharness_element_grid.html new file mode 100644 index 0000000000..b8f0ffe020 --- /dev/null +++ b/testing/web-platform/tests/html/canvas/tools/templates/testharness_element_grid.html @@ -0,0 +1,52 @@ +<!DOCTYPE html> +<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. --> +<title>Canvas test: {{ name }}</title> +{% if timeout %}<meta name="timeout" content="{{ timeout }}">{% endif %} +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/html/canvas/resources/canvas-tests.js"></script> +<link rel="stylesheet" href="/html/canvas/resources/canvas-tests.css"> + +{% if fonts %} +<style> +{% for font in fonts %} + @font-face { + font-family: {{ font }}; + src: url("/fonts/{{ font }}.ttf"); + } +{% endfor %} +</style> +{% if not font_unused_in_dom %} +{% for font in fonts %} +<span style="font-family: {{ font }}; + position: absolute; visibility: hidden">A</span> +{% endfor %} +{% endif %} +{% endif %} +{% for image in images %} +<img src="/images/{{ image }}" id="{{ image }}" class="resource"> +{% endfor %} +{% for svgimage in svgimages %} +<svg><image xlink:href="/images/{{ svgimage }}" id="{{ svgimage + }}" class="resource"></svg> +{% endfor %} +<script> +{% for variant in element_variants %} + +{% if test_type == 'promise' %} +promise_test(async t => { +{% elif test_type == 'async' %} +async_test(t => { +{% else %} +test(t => { +{% endif %} + const canvas = document.createElement('canvas'); + const ctx = canvas.getContext('2d'{% + if attributes %}, {{ variant.attributes }}{% endif %}); + + {{ variant.code_element | trim | indent(2) }} +}, "{{ variant.desc | double_quote_escape }}"); +{% endfor %} + +</script> +</div> diff --git a/testing/web-platform/tests/html/canvas/tools/templates/testharness_offscreen_grid.html b/testing/web-platform/tests/html/canvas/tools/templates/testharness_offscreen_grid.html new file mode 100644 index 0000000000..6e5628036b --- /dev/null +++ b/testing/web-platform/tests/html/canvas/tools/templates/testharness_offscreen_grid.html @@ -0,0 +1,28 @@ +<!DOCTYPE html> +<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. --> +<title>OffscreenCanvas test: {{ name }}</title> +{% if timeout %}<meta name="timeout" content="{{ timeout }}">{% endif %} +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/html/canvas/resources/canvas-tests.js"></script> + +<script> +{% for variant in offscreen_variants %} + +{% if test_type == 'promise' %} +promise_test(async t => { +{% elif test_type == 'async' %} +async_test(t => { +{% else %} +test(t => { +{% endif %} + const canvas = new OffscreenCanvas({{ + variant.size[0] }}, {{ variant.size[1] }}); + const ctx = canvas.getContext('2d'{% + if variant.attributes %}, {{ variant.attributes }}{% endif %}); + + {{ variant.code_offscreen | trim | indent(2)}} +}, "{{ variant.desc | double_quote_escape }}"); +{% endfor %} + +</script> diff --git a/testing/web-platform/tests/html/canvas/tools/templates/testharness_worker_grid.js b/testing/web-platform/tests/html/canvas/tools/templates/testharness_worker_grid.js new file mode 100644 index 0000000000..53c3b69cb6 --- /dev/null +++ b/testing/web-platform/tests/html/canvas/tools/templates/testharness_worker_grid.js @@ -0,0 +1,27 @@ +{% if timeout %}// META: timeout={{ timeout }}{% endif %} +// DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. +// OffscreenCanvas test in a worker:{{ name }} +// Description:{{ desc }} +// Note:{% if notes %}<p class="notes">{{ notes }}{% endif +%} + +importScripts("/resources/testharness.js"); +importScripts("/html/canvas/resources/canvas-tests.js"); +{% for variant in worker_variants %} + +{% if test_type == 'promise' %} +promise_test(async t => { +{% elif test_type == 'async' %} +async_test(t => { +{% else %} +test(t => { +{% endif %} + const canvas = new OffscreenCanvas({{ + variant.size[0] }}, {{ variant.size[1] }}); + const ctx = canvas.getContext('2d'{% + if variant.attributes %}, {{ variant.attributes }}{% endif %}); + + {{ variant.code_worker | trim | indent(2)}} +}, "{{ variant.desc | double_quote_escape }}"); +{% endfor %} + +done(); diff --git a/testing/web-platform/tests/html/canvas/tools/yaml-new/filters.yaml b/testing/web-platform/tests/html/canvas/tools/yaml-new/filters.yaml index 1ce9d8ed74..9a738a37bd 100644 --- a/testing/web-platform/tests/html/canvas/tools/yaml-new/filters.yaml +++ b/testing/web-platform/tests/html/canvas/tools/yaml-new/filters.yaml @@ -617,8 +617,7 @@ tentative: .tentative - name: >- - 2d.filter.{{ variant_names[0] }}.gaussianBlur.{{ variant_names[1] }}{{ - tentative }} + 2d.filter.{{ variant_names[0] }}.gaussianBlur{{ tentative }} desc: Test CanvasFilter() with gaussianBlur. size: [100, 100] code: | @@ -633,13 +632,14 @@ <svg xmlns="http://www.w3.org/2000/svg" width="{{ size[0] }}" height="{{ size[1] }}" color-interpolation-filters="sRGB"> - <filter id="blur" x="-50%" y="-50%" width="200%" height="200%"> + <filter id="blur{{ id }}" x="-50%" y="-50%" width="200%" height="200%"> <feGaussianBlur stdDeviation="{{ blur_x }} {{blur_y}}" /> </filter> <rect x="25" y="25" width="50" height="50" - fill="teal" filter="url(#blur)" /> + fill="teal" filter="url(#blur{{ id }})" /> </svg> append_variants_to_name: false + variants_layout: [multi_files, single_file] variants: - layers: filter_declaration: |- diff --git a/testing/web-platform/tests/html/canvas/tools/yaml-new/layers.yaml b/testing/web-platform/tests/html/canvas/tools/yaml-new/layers.yaml index d1e9a97043..e71155650b 100644 --- a/testing/web-platform/tests/html/canvas/tools/yaml-new/layers.yaml +++ b/testing/web-platform/tests/html/canvas/tools/yaml-new/layers.yaml @@ -1,14 +1,15 @@ - name: 2d.layer.global-states desc: Checks that layers correctly use global render states. - size: [200, 200] + size: [90, 90] code: | - ctx.fillStyle = 'rgba(0, 0, 255, 1)'; + {{ transform_statement }} - var circle = new Path2D(); - circle.arc(90, 90, 45, 0, 2 * Math.PI); - ctx.fill(circle); + ctx.fillStyle = 'rgba(128, 128, 128, 1)'; + ctx.fillRect(20, 15, 50, 50); - {{ render_states }} + {{ alpha_statement }} + {{ composite_op_statement }} + {{ shadow_statement }} ctx.beginLayer(); @@ -16,118 +17,86 @@ // won't individually composite with the background. ctx.globalCompositeOperation = 'screen'; - ctx.fillStyle = 'rgba(225, 0, 0, 1)'; - ctx.fillRect(50, 50, 75, 50); + ctx.fillStyle = 'rgba(255, 0, 0, 1)'; + ctx.fillRect(10, 25, 40, 50); ctx.fillStyle = 'rgba(0, 255, 0, 1)'; - ctx.fillRect(70, 70, 75, 50); + ctx.fillRect(30, 5, 50, 40); ctx.endLayer(); reference: | - ctx.fillStyle = 'rgba(0, 0, 255, 1)'; + {{ transform_statement }} - var circle = new Path2D(); - circle.arc(90, 90, 45, 0, 2 * Math.PI); - ctx.fill(circle); + ctx.fillStyle = 'rgba(128, 128, 128, 1)'; + ctx.fillRect(20, 15, 50, 50); - {{ render_states }} + {{ alpha_statement }} + {{ composite_op_statement }} + {{ shadow_statement }} - canvas2 = document.createElement("canvas"); - ctx2 = canvas2.getContext("2d"); + const canvas2 = document.createElement("canvas"); + const ctx2 = canvas2.getContext("2d"); ctx2.globalCompositeOperation = 'screen'; - ctx2.fillStyle = 'rgba(225, 0, 0, 1)'; - ctx2.fillRect(50, 50, 75, 50); + ctx2.fillStyle = 'rgba(255, 0, 0, 1)'; + ctx2.fillRect(10, 25, 40, 50); ctx2.fillStyle = 'rgba(0, 255, 0, 1)'; - ctx2.fillRect(70, 70, 75, 50); + ctx2.fillRect(30, 5, 50, 40); ctx.drawImage(canvas2, 0, 0); - variants: - - &global-state-variants - no-global-states: - render_states: // No global states. - alpha: &global-state-alpha - render_states: ctx.globalAlpha = 0.6; + variants_layout: [single_file, multi_files, multi_files, multi_files] + variants: &global-state-variants + - no-globalAlpha: + alpha_statement: // No globalAlpha. + globalAlpha: + alpha_statement: ctx.globalAlpha = 0.75; + - no-composite-op: + composite_op_statement: // No globalCompositeOperation. blending: - render_states: ctx.globalCompositeOperation = 'multiply'; + composite_op_statement: ctx.globalCompositeOperation = 'multiply'; composite: - render_states: ctx.globalCompositeOperation = 'source-in'; + composite_op_statement: ctx.globalCompositeOperation = 'source-in'; + copy: + composite_op_statement: ctx.globalCompositeOperation = 'copy'; + - no-shadow: + shadow_statement: // No shadow. shadow: - render_states: |- - ctx.shadowOffsetX = -10; - ctx.shadowOffsetY = 10; - ctx.shadowColor = 'rgba(255, 165, 0, 0.5)'; - ctx.shadowBlur = 3; - alpha.blending: &global-state-alpha-blending - render_states: |- - ctx.globalAlpha = 0.6; - ctx.globalCompositeOperation = 'multiply'; - alpha.composite: &global-state-alpha-composite - render_states: |- - ctx.globalAlpha = 0.6; - ctx.globalCompositeOperation = 'source-in'; - alpha.shadow: &global-state-alpha-shadow - render_states: |- - ctx.globalAlpha = 0.5; - ctx.shadowOffsetX = -10; - ctx.shadowOffsetY = 10; - ctx.shadowColor = 'rgba(255, 165, 0, 0.5)'; - ctx.shadowBlur = 3; - alpha.blending.shadow: - render_states: |- - ctx.globalAlpha = 0.6; - ctx.globalCompositeOperation = 'multiply'; - ctx.shadowOffsetX = -10; - ctx.shadowOffsetY = 10; - ctx.shadowColor = 'rgba(255, 165, 0, 0.5)'; - ctx.shadowBlur = 3; - alpha.composite.shadow: - render_states: |- - ctx.globalAlpha = 0.6; - ctx.globalCompositeOperation = 'source-in'; - ctx.shadowOffsetX = -10; - ctx.shadowOffsetY = 10; - ctx.shadowColor = 'rgba(255, 165, 0, 0.5)'; - ctx.shadowBlur = 3; - blending.shadow: - render_states: |- - ctx.globalCompositeOperation = 'multiply'; - ctx.shadowOffsetX = -10; - ctx.shadowOffsetY = 10; - ctx.shadowColor = 'rgba(255, 165, 0, 0.5)'; - ctx.shadowBlur = 3; - composite.shadow: - render_states: |- - ctx.globalCompositeOperation = 'source-in'; - ctx.shadowOffsetX = -10; - ctx.shadowOffsetY = 10; + shadow_statement: |- + ctx.shadowOffsetX = -7; + ctx.shadowOffsetY = 7; ctx.shadowColor = 'rgba(255, 165, 0, 0.5)'; ctx.shadowBlur = 3; + - no-transform: + transform_statement: // No transform. + rotation: + transform_statement: |- + ctx.translate(50, 40); + ctx.rotate(Math.PI); + ctx.translate(-45, -45); + - name: 2d.layer.global-states.filter desc: Checks that layers with filters correctly use global render states. - size: [200, 200] + size: [90, 90] code: | - ctx.fillStyle = 'rgba(0, 0, 255, 1)'; + {{ transform_statement }} - var circle = new Path2D(); - circle.arc(90, 90, 45, 0, 2 * Math.PI); - ctx.fill(circle); + ctx.fillStyle = 'rgba(128, 128, 128, 1)'; + ctx.fillRect(20, 15, 50, 50); - {{ render_states }} + {{ alpha_statement }} + {{ composite_op_statement }} + {{ shadow_statement }} ctx.beginLayer({filter: [ - {name: 'colorMatrix', values: [0.393, 0.769, 0.189, 0, 0, - 0.349, 0.686, 0.168, 0, 0, - 0.272, 0.534, 0.131, 0, 0, - 0, 0, 0, 1, 0]}, + {name: 'dropShadow', + dx: 5, dy: 5, stdDeviation: 0, floodColor: '#00f'}, {name: 'componentTransfer', - funcA: {type: "table", tableValues: [0, 0.7]}}, - {name: 'dropShadow', dx: 5, dy: 5, floodColor: '#81e'}]}); + funcA: {type: "table", tableValues: [0, 0.8]}}]}); - ctx.fillStyle = 'rgba(200, 0, 0, 1)'; - ctx.fillRect(50, 50, 75, 50); - ctx.fillStyle = 'rgba(0, 200, 0, 1)'; - ctx.fillRect(70, 70, 75, 50); + ctx.fillStyle = 'rgba(255, 0, 0, 1)'; + ctx.fillRect(10, 25, 40, 50); + ctx.fillStyle = 'rgba(0, 255, 0, 1)'; + ctx.fillRect(30, 5, 50, 40); ctx.endLayer(); reference: | @@ -136,20 +105,14 @@ width="{{ size[0] }}" height="{{ size[1] }}" color-interpolation-filters="sRGB"> <filter id="filter" x="-100%" y="-100%" width="300%" height="300%"> - <feColorMatrix - type="matrix" - values="0.393 0.769 0.189 0 0 - 0.349 0.686 0.168 0 0 - 0.272 0.534 0.131 0 0 - 0 0 0 1 0" /> + <feDropShadow dx="5" dy="5" stdDeviation="0" flood-color="#00f" /> <feComponentTransfer> - <feFuncA type="table" tableValues="0 0.7"></feFuncA> + <feFuncA type="table" tableValues="0 0.8"></feFuncA> </feComponentTransfer> - <feDropShadow dx="5" dy="5" flood-color="#81e" /> </filter> <g filter="url(#filter)"> - <rect x="50" y="50" width="75" height="50" fill="rgba(200, 0, 0, 1)"/> - <rect x="70" y="70" width="75" height="50" fill="rgba(0, 200, 0, 1)"/> + <rect x="10" y="25" width="40" height="50" fill="rgba(255, 0, 0, 1)"/> + <rect x="30" y="5" width="50" height="40" fill="rgba(0, 255, 0, 1)"/> </g> </svg>`; @@ -157,31 +120,100 @@ img.width = {{ size[0] }}; img.height = {{ size[1] }}; img.onload = () => { - ctx.fillStyle = 'rgba(0, 0, 255, 1)'; + {{ transform_statement | indent(2) }} - var circle = new Path2D(); - circle.arc(90, 90, 45, 0, 2 * Math.PI); - ctx.fill(circle); + ctx.fillStyle = 'rgba(128, 128, 128, 1)'; + ctx.fillRect(20, 15, 50, 50); - {{ render_states }} + {{ alpha_statement | indent(2) }} + {{ composite_op_statement | indent(2) }} + {{ shadow_statement | indent(2) }} ctx.drawImage(img, 0, 0); }; img.src = 'data:image/svg+xml;base64,' + btoa(svg); + variants_layout: [single_file, multi_files, multi_files, multi_files] + variants: *global-state-variants + +- name: 2d.layer.globalCompositeOperation + desc: Checks that layers work with all globalCompositeOperation values. + size: [90, 90] + code: | + ctx.translate(50, 50); + ctx.scale(2, 2); + ctx.rotate(Math.PI); + ctx.translate(-25, -25); + + ctx.fillStyle = 'rgba(0, 0, 255, 0.8)'; + ctx.fillRect(15, 15, 25, 25); + + ctx.globalAlpha = 0.75; + ctx.globalCompositeOperation = '{{ variant_names[0] }}'; + ctx.shadowOffsetX = 7; + ctx.shadowOffsetY = 7; + ctx.shadowColor = 'rgba(255, 165, 0, 0.5)'; + + ctx.beginLayer(); + + ctx.fillStyle = 'rgba(204, 0, 0, 1)'; + ctx.fillRect(10, 25, 25, 20); + ctx.fillStyle = 'rgba(0, 204, 0, 1)'; + ctx.fillRect(25, 10, 20, 25); + + ctx.endLayer(); + reference: | + ctx.translate(50, 50); + ctx.scale(2, 2); + ctx.rotate(Math.PI); + ctx.translate(-25, -25); + + ctx.fillStyle = 'rgba(0, 0, 255, 0.8)'; + ctx.fillRect(15, 15, 25, 25); + + ctx.globalAlpha = 0.75; + ctx.globalCompositeOperation = '{{ variant_names[0] }}'; + ctx.shadowOffsetX = 7; + ctx.shadowOffsetY = 7; + ctx.shadowColor = 'rgba(255, 165, 0, 0.5)'; + + const canvas2 = document.createElement("canvas"); + const ctx2 = canvas2.getContext("2d"); + + ctx2.fillStyle = 'rgba(204, 0, 0, 1)'; + ctx2.fillRect(10, 25, 25, 20); + ctx2.fillStyle = 'rgba(0, 204, 0, 1)'; + ctx2.fillRect(25, 10, 20, 25); + + ctx.imageSmoothingEnabled = false; + ctx.drawImage(canvas2, 0, 0); + variants_layout: [single_file] + grid_width: 7 variants: - - <<: *global-state-variants - alpha: - <<: *global-state-alpha - fuzzy: maxDifference=0-2; totalPixels=0-6766 - alpha.blending: - <<: *global-state-alpha-blending - fuzzy: maxDifference=0-1; totalPixels=0-2453 - alpha.composite: - <<: *global-state-alpha-composite - fuzzy: maxDifference=0-1; totalPixels=0-5204 - alpha.shadow: - <<: *global-state-alpha-shadow - fuzzy: maxDifference=0-2; totalPixels=0-6311 + - source-over: + source-in: + source-atop: + destination-over: + destination-in: + destination-out: + destination-atop: + lighter: + copy: + xor: + multiply: + screen: + overlay: + darken: + lighten: + color-dodge: + color-burn: + hard-light: + soft-light: + difference: + exclusion: + hue: + saturation: + color: + luminosity: - name: 2d.layer.global-filter desc: Tests that layers ignore the global context filter. @@ -428,6 +460,7 @@ - name: 2d.layer.ctm.getTransform desc: Tests getTransform inside layers. + test_type: sync code: | ctx.translate(10, 20); ctx.beginLayer(); @@ -559,7 +592,7 @@ desc: Check that layers state stack is flushed and rebuilt on frame renders. size: [200, 200] canvas_types: ['HtmlCanvas'] - test_type: "promise" + test_type: promise code: | ctx.fillStyle = 'purple'; ctx.fillRect(60, 60, 75, 50); @@ -599,10 +632,9 @@ ctx.fillRect(80, 40, 75, 50); - name: 2d.layer.malformed-operations - desc: >- - Check that exceptions are thrown for operations that are malformed while - layers are open. + desc: Throws if {{ variant_names[0] }} is called while layers are open. size: [200, 200] + test_type: sync code: | {{ setup }} // Shouldn't throw on its own. @@ -613,6 +645,7 @@ ctx.beginLayer(); assert_throws_dom("InvalidStateError", () => {{ operation }}); + variants_layout: [single_file] variants: - createPattern: operation: ctx.createPattern(canvas, 'repeat') @@ -639,11 +672,9 @@ operation: canvas.transferToImageBitmap() - name: 2d.layer.malformed-operations-with-promises - desc: >- - Check that exceptions are thrown for operations that are malformed while - layers are open. + desc: Throws if {{ variant_names[0] }} is called while layers are open. size: [200, 200] - test_type: "promise" + test_type: promise code: | // Shouldn't throw on its own. await {{ operation }}; @@ -651,7 +682,9 @@ await {{ operation }}; // Calling again inside a layer should throw. ctx.beginLayer(); - await promise_rejects_dom(t, 'InvalidStateError', {{ operation }}); + await promise_rejects_dom(t, 'InvalidStateError', + {{ operation }}); + variants_layout: [single_file] variants: - convertToBlob: canvas_types: ['OffscreenCanvas', 'Worker'] @@ -864,6 +897,7 @@ - name: 2d.layer.invalid-calls desc: Raises exception on {{ variant_desc }}. + test_type: sync code: | assert_throws_dom("INVALID_STATE_ERR", function() { {{ call_sequence | indent(2) }} @@ -903,6 +937,7 @@ - name: 2d.layer.exceptions-are-no-op desc: Checks that the context state is left unchanged if beginLayer throws. + test_type: sync code: | // Get `beginLayer` to throw while parsing the filter. assert_throws_js(TypeError, @@ -927,6 +962,7 @@ - name: 2d.layer.beginLayer-options desc: Checks beginLayer works for different option parameter values + test_type: sync code: | ctx.beginLayer(); ctx.endLayer(); ctx.beginLayer(null); ctx.endLayer(); 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 index 5fd8b68498..12852e200a 100644 --- a/testing/web-platform/tests/html/canvas/tools/yaml/element/meta.yaml +++ b/testing/web-platform/tests/html/canvas/tools/yaml/element/meta.yaml @@ -390,18 +390,12 @@ ('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, ""), + ('hsl-clamp-negative-saturation', 'hsl(120, -200%, 49.9%)', 127,127,127,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, ""), + ('hsla-clamp-negative-saturation', 'hsla(120, -200%, 49.9%, 1)', 127,127,127,255, ""), + ('hsla-clamp-alpha-1', 'hsla(120, 100%, 50%, 2)', 0,255,0,255, ""), + ('hsla-clamp-alpha-2', '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 diff --git a/testing/web-platform/tests/html/canvas/tools/yaml/offscreen/meta.yaml b/testing/web-platform/tests/html/canvas/tools/yaml/offscreen/meta.yaml index 7b44fd9f26..b07898224d 100644 --- a/testing/web-platform/tests/html/canvas/tools/yaml/offscreen/meta.yaml +++ b/testing/web-platform/tests/html/canvas/tools/yaml/offscreen/meta.yaml @@ -346,18 +346,12 @@ ('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, ""), + ('hsl-clamp-negative-saturation', 'hsl(120, -200%, 49.9%)', 127,127,127,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, ""), + ('hsla-clamp-negative-saturation', 'hsla(120, -200%, 49.9%, 1)', 127,127,127,255, ""), + ('hsla-clamp-alpha-1', 'hsla(120, 100%, 50%, 2)', 0,255,0,255, ""), + ('hsla-clamp-alpha-2', '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 |