summaryrefslogtreecommitdiffstats
path: root/testing/web-platform/tests/html
diff options
context:
space:
mode:
Diffstat (limited to 'testing/web-platform/tests/html')
-rw-r--r--testing/web-platform/tests/html/browsers/browsing-the-web/scroll-to-fragid/scroll-position-inline-nearest.html30
-rw-r--r--testing/web-platform/tests/html/canvas/element/fill-and-stroke-styles/2d.fillStyle.parse.hsl-clamp-1.html29
-rw-r--r--testing/web-platform/tests/html/canvas/element/fill-and-stroke-styles/2d.fillStyle.parse.hsl-clamp-3.html29
-rw-r--r--testing/web-platform/tests/html/canvas/element/fill-and-stroke-styles/2d.fillStyle.parse.hsl-clamp-3.pngbin207 -> 0 bytes
-rw-r--r--testing/web-platform/tests/html/canvas/element/fill-and-stroke-styles/2d.fillStyle.parse.hsl-clamp-4.html29
-rw-r--r--testing/web-platform/tests/html/canvas/element/fill-and-stroke-styles/2d.fillStyle.parse.hsl-clamp-4.pngbin112 -> 0 bytes
-rw-r--r--testing/web-platform/tests/html/canvas/element/fill-and-stroke-styles/2d.fillStyle.parse.hsl-clamp-negative-saturation.html (renamed from testing/web-platform/tests/html/canvas/element/fill-and-stroke-styles/2d.fillStyle.parse.hsl-clamp-2.html)6
-rw-r--r--testing/web-platform/tests/html/canvas/element/fill-and-stroke-styles/2d.fillStyle.parse.hsl-clamp-negative-saturation.png (renamed from testing/web-platform/tests/html/canvas/element/fill-and-stroke-styles/2d.fillStyle.parse.hsl-clamp-2.png)bin207 -> 207 bytes
-rw-r--r--testing/web-platform/tests/html/canvas/element/fill-and-stroke-styles/2d.fillStyle.parse.hsla-clamp-1.html29
-rw-r--r--testing/web-platform/tests/html/canvas/element/fill-and-stroke-styles/2d.fillStyle.parse.hsla-clamp-1.pngbin205 -> 0 bytes
-rw-r--r--testing/web-platform/tests/html/canvas/element/fill-and-stroke-styles/2d.fillStyle.parse.hsla-clamp-3.html29
-rw-r--r--testing/web-platform/tests/html/canvas/element/fill-and-stroke-styles/2d.fillStyle.parse.hsla-clamp-3.pngbin207 -> 0 bytes
-rw-r--r--testing/web-platform/tests/html/canvas/element/fill-and-stroke-styles/2d.fillStyle.parse.hsla-clamp-4.html29
-rw-r--r--testing/web-platform/tests/html/canvas/element/fill-and-stroke-styles/2d.fillStyle.parse.hsla-clamp-4.pngbin112 -> 0 bytes
-rw-r--r--testing/web-platform/tests/html/canvas/element/fill-and-stroke-styles/2d.fillStyle.parse.hsla-clamp-5.pngbin205 -> 0 bytes
-rw-r--r--testing/web-platform/tests/html/canvas/element/fill-and-stroke-styles/2d.fillStyle.parse.hsla-clamp-alpha-1.html (renamed from testing/web-platform/tests/html/canvas/element/fill-and-stroke-styles/2d.fillStyle.parse.hsla-clamp-5.html)6
-rw-r--r--testing/web-platform/tests/html/canvas/element/fill-and-stroke-styles/2d.fillStyle.parse.hsla-clamp-alpha-1.png (renamed from testing/web-platform/tests/html/canvas/element/fill-and-stroke-styles/2d.fillStyle.parse.hsl-clamp-1.png)bin205 -> 205 bytes
-rw-r--r--testing/web-platform/tests/html/canvas/element/fill-and-stroke-styles/2d.fillStyle.parse.hsla-clamp-alpha-2.html (renamed from testing/web-platform/tests/html/canvas/element/fill-and-stroke-styles/2d.fillStyle.parse.hsla-clamp-6.html)6
-rw-r--r--testing/web-platform/tests/html/canvas/element/fill-and-stroke-styles/2d.fillStyle.parse.hsla-clamp-alpha-2.png (renamed from testing/web-platform/tests/html/canvas/element/fill-and-stroke-styles/2d.fillStyle.parse.hsla-clamp-6.png)bin117 -> 117 bytes
-rw-r--r--testing/web-platform/tests/html/canvas/element/fill-and-stroke-styles/2d.fillStyle.parse.hsla-clamp-negative-saturation.html (renamed from testing/web-platform/tests/html/canvas/element/fill-and-stroke-styles/2d.fillStyle.parse.hsla-clamp-2.html)6
-rw-r--r--testing/web-platform/tests/html/canvas/element/fill-and-stroke-styles/2d.fillStyle.parse.hsla-clamp-negative-saturation.png (renamed from testing/web-platform/tests/html/canvas/element/fill-and-stroke-styles/2d.fillStyle.parse.hsla-clamp-2.png)bin207 -> 207 bytes
-rw-r--r--testing/web-platform/tests/html/canvas/element/filters/2d.filter.canvasFilterObject.gaussianBlur.isotropic.tentative-expected.html15
-rw-r--r--testing/web-platform/tests/html/canvas/element/filters/2d.filter.canvasFilterObject.gaussianBlur.isotropic.tentative.html20
-rw-r--r--testing/web-platform/tests/html/canvas/element/filters/2d.filter.canvasFilterObject.gaussianBlur.mostly-x.tentative-expected.html15
-rw-r--r--testing/web-platform/tests/html/canvas/element/filters/2d.filter.canvasFilterObject.gaussianBlur.mostly-x.tentative.html20
-rw-r--r--testing/web-platform/tests/html/canvas/element/filters/2d.filter.canvasFilterObject.gaussianBlur.mostly-y.tentative-expected.html15
-rw-r--r--testing/web-platform/tests/html/canvas/element/filters/2d.filter.canvasFilterObject.gaussianBlur.mostly-y.tentative.html20
-rw-r--r--testing/web-platform/tests/html/canvas/element/filters/2d.filter.canvasFilterObject.gaussianBlur.tentative-expected.html85
-rw-r--r--testing/web-platform/tests/html/canvas/element/filters/2d.filter.canvasFilterObject.gaussianBlur.tentative.html101
-rw-r--r--testing/web-platform/tests/html/canvas/element/filters/2d.filter.canvasFilterObject.gaussianBlur.x-only.tentative-expected.html15
-rw-r--r--testing/web-platform/tests/html/canvas/element/filters/2d.filter.canvasFilterObject.gaussianBlur.x-only.tentative.html20
-rw-r--r--testing/web-platform/tests/html/canvas/element/filters/2d.filter.canvasFilterObject.gaussianBlur.y-only.tentative-expected.html15
-rw-r--r--testing/web-platform/tests/html/canvas/element/filters/2d.filter.canvasFilterObject.gaussianBlur.y-only.tentative.html20
-rw-r--r--testing/web-platform/tests/html/canvas/element/filters/2d.filter.layers.gaussianBlur-expected.html85
-rw-r--r--testing/web-platform/tests/html/canvas/element/filters/2d.filter.layers.gaussianBlur.html106
-rw-r--r--testing/web-platform/tests/html/canvas/element/filters/2d.filter.layers.gaussianBlur.isotropic-expected.html15
-rw-r--r--testing/web-platform/tests/html/canvas/element/filters/2d.filter.layers.gaussianBlur.isotropic.html21
-rw-r--r--testing/web-platform/tests/html/canvas/element/filters/2d.filter.layers.gaussianBlur.mostly-x-expected.html15
-rw-r--r--testing/web-platform/tests/html/canvas/element/filters/2d.filter.layers.gaussianBlur.mostly-x.html21
-rw-r--r--testing/web-platform/tests/html/canvas/element/filters/2d.filter.layers.gaussianBlur.mostly-y-expected.html15
-rw-r--r--testing/web-platform/tests/html/canvas/element/filters/2d.filter.layers.gaussianBlur.mostly-y.html21
-rw-r--r--testing/web-platform/tests/html/canvas/element/filters/2d.filter.layers.gaussianBlur.x-only-expected.html15
-rw-r--r--testing/web-platform/tests/html/canvas/element/filters/2d.filter.layers.gaussianBlur.x-only.html21
-rw-r--r--testing/web-platform/tests/html/canvas/element/filters/2d.filter.layers.gaussianBlur.y-only-expected.html15
-rw-r--r--testing/web-platform/tests/html/canvas/element/filters/2d.filter.layers.gaussianBlur.y-only.html21
-rw-r--r--testing/web-platform/tests/html/canvas/element/layers/2d.layer.beginLayer-options.html7
-rw-r--r--testing/web-platform/tests/html/canvas/element/layers/2d.layer.ctm.getTransform.html7
-rw-r--r--testing/web-platform/tests/html/canvas/element/layers/2d.layer.exceptions-are-no-op.html7
-rw-r--r--testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.alpha-expected.html31
-rw-r--r--testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.alpha.blending-expected.html32
-rw-r--r--testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.alpha.blending.html35
-rw-r--r--testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.alpha.blending.shadow-expected.html36
-rw-r--r--testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.alpha.blending.shadow.html39
-rw-r--r--testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.alpha.composite-expected.html32
-rw-r--r--testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.alpha.composite.html35
-rw-r--r--testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.alpha.composite.shadow-expected.html36
-rw-r--r--testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.alpha.composite.shadow.html39
-rw-r--r--testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.alpha.html34
-rw-r--r--testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.alpha.shadow-expected.html35
-rw-r--r--testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.alpha.shadow.html38
-rw-r--r--testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.blending-expected.html31
-rw-r--r--testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.blending.html34
-rw-r--r--testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.blending.no-shadow.no-transform-expected.html72
-rw-r--r--testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.blending.no-shadow.no-transform.html77
-rw-r--r--testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.blending.no-shadow.rotation-expected.html76
-rw-r--r--testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.blending.no-shadow.rotation.html81
-rw-r--r--testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.blending.shadow-expected.html35
-rw-r--r--testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.blending.shadow.html38
-rw-r--r--testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.blending.shadow.no-transform-expected.html78
-rw-r--r--testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.blending.shadow.no-transform.html83
-rw-r--r--testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.blending.shadow.rotation-expected.html82
-rw-r--r--testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.blending.shadow.rotation.html87
-rw-r--r--testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.composite-expected.html31
-rw-r--r--testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.composite.html34
-rw-r--r--testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.composite.no-shadow.no-transform-expected.html72
-rw-r--r--testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.composite.no-shadow.no-transform.html77
-rw-r--r--testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.composite.no-shadow.rotation-expected.html76
-rw-r--r--testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.composite.no-shadow.rotation.html81
-rw-r--r--testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.composite.shadow-expected.html35
-rw-r--r--testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.composite.shadow.html38
-rw-r--r--testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.composite.shadow.no-transform-expected.html78
-rw-r--r--testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.composite.shadow.no-transform.html83
-rw-r--r--testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.composite.shadow.rotation-expected.html82
-rw-r--r--testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.composite.shadow.rotation.html87
-rw-r--r--testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.copy.no-shadow.no-transform-expected.html72
-rw-r--r--testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.copy.no-shadow.no-transform.html77
-rw-r--r--testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.copy.no-shadow.rotation-expected.html76
-rw-r--r--testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.copy.no-shadow.rotation.html81
-rw-r--r--testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.copy.shadow.no-transform-expected.html78
-rw-r--r--testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.copy.shadow.no-transform.html83
-rw-r--r--testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.copy.shadow.rotation-expected.html82
-rw-r--r--testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.copy.shadow.rotation.html87
-rw-r--r--testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.alpha-expected.html50
-rw-r--r--testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.alpha.blending-expected.html51
-rw-r--r--testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.alpha.blending.html39
-rw-r--r--testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.alpha.blending.shadow-expected.html55
-rw-r--r--testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.alpha.blending.shadow.html42
-rw-r--r--testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.alpha.composite-expected.html51
-rw-r--r--testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.alpha.composite.html39
-rw-r--r--testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.alpha.composite.shadow-expected.html55
-rw-r--r--testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.alpha.composite.shadow.html42
-rw-r--r--testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.alpha.html38
-rw-r--r--testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.alpha.shadow-expected.html54
-rw-r--r--testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.alpha.shadow.html42
-rw-r--r--testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.blending-expected.html50
-rw-r--r--testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.blending.html37
-rw-r--r--testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.blending.no-shadow.no-transform-expected.html98
-rw-r--r--testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.blending.no-shadow.no-transform.html77
-rw-r--r--testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.blending.no-shadow.rotation-expected.html102
-rw-r--r--testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.blending.no-shadow.rotation.html81
-rw-r--r--testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.blending.shadow-expected.html54
-rw-r--r--testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.blending.shadow.html41
-rw-r--r--testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.blending.shadow.no-transform-expected.html104
-rw-r--r--testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.blending.shadow.no-transform.html83
-rw-r--r--testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.blending.shadow.rotation-expected.html108
-rw-r--r--testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.blending.shadow.rotation.html87
-rw-r--r--testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.composite-expected.html50
-rw-r--r--testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.composite.html37
-rw-r--r--testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.composite.no-shadow.no-transform-expected.html98
-rw-r--r--testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.composite.no-shadow.no-transform.html77
-rw-r--r--testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.composite.no-shadow.rotation-expected.html102
-rw-r--r--testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.composite.no-shadow.rotation.html81
-rw-r--r--testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.composite.shadow-expected.html54
-rw-r--r--testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.composite.shadow.html41
-rw-r--r--testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.composite.shadow.no-transform-expected.html104
-rw-r--r--testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.composite.shadow.no-transform.html83
-rw-r--r--testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.composite.shadow.rotation-expected.html108
-rw-r--r--testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.composite.shadow.rotation.html87
-rw-r--r--testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.copy.no-shadow.no-transform-expected.html98
-rw-r--r--testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.copy.no-shadow.no-transform.html77
-rw-r--r--testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.copy.no-shadow.rotation-expected.html102
-rw-r--r--testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.copy.no-shadow.rotation.html81
-rw-r--r--testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.copy.shadow.no-transform-expected.html104
-rw-r--r--testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.copy.shadow.no-transform.html83
-rw-r--r--testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.copy.shadow.rotation-expected.html108
-rw-r--r--testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.copy.shadow.rotation.html87
-rw-r--r--testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.no-composite-op.no-shadow.no-transform-expected.html98
-rw-r--r--testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.no-composite-op.no-shadow.no-transform.html77
-rw-r--r--testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.no-composite-op.no-shadow.rotation-expected.html102
-rw-r--r--testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.no-composite-op.no-shadow.rotation.html81
-rw-r--r--testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.no-composite-op.shadow.no-transform-expected.html104
-rw-r--r--testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.no-composite-op.shadow.no-transform.html83
-rw-r--r--testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.no-composite-op.shadow.rotation-expected.html108
-rw-r--r--testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.no-composite-op.shadow.rotation.html87
-rw-r--r--testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.no-global-states-expected.html50
-rw-r--r--testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.no-global-states.html37
-rw-r--r--testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.shadow-expected.html53
-rw-r--r--testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.shadow.html40
-rw-r--r--testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.no-composite-op.no-shadow.no-transform-expected.html72
-rw-r--r--testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.no-composite-op.no-shadow.no-transform.html77
-rw-r--r--testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.no-composite-op.no-shadow.rotation-expected.html76
-rw-r--r--testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.no-composite-op.no-shadow.rotation.html81
-rw-r--r--testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.no-composite-op.shadow.no-transform-expected.html78
-rw-r--r--testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.no-composite-op.shadow.no-transform.html83
-rw-r--r--testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.no-composite-op.shadow.rotation-expected.html82
-rw-r--r--testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.no-composite-op.shadow.rotation.html87
-rw-r--r--testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.no-global-states-expected.html31
-rw-r--r--testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.no-global-states.html34
-rw-r--r--testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.shadow-expected.html34
-rw-r--r--testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.shadow.html37
-rw-r--r--testing/web-platform/tests/html/canvas/element/layers/2d.layer.globalCompositeOperation-expected.html910
-rw-r--r--testing/web-platform/tests/html/canvas/element/layers/2d.layer.globalCompositeOperation.html861
-rw-r--r--testing/web-platform/tests/html/canvas/element/layers/2d.layer.invalid-calls.beginLayer-reset-endLayer.html7
-rw-r--r--testing/web-platform/tests/html/canvas/element/layers/2d.layer.invalid-calls.beginLayer-restore.html7
-rw-r--r--testing/web-platform/tests/html/canvas/element/layers/2d.layer.invalid-calls.beginLayer-save-endLayer.html7
-rw-r--r--testing/web-platform/tests/html/canvas/element/layers/2d.layer.invalid-calls.endLayer.html7
-rw-r--r--testing/web-platform/tests/html/canvas/element/layers/2d.layer.invalid-calls.save-beginLayer-restore.html7
-rw-r--r--testing/web-platform/tests/html/canvas/element/layers/2d.layer.invalid-calls.save-endLayer.html7
-rw-r--r--testing/web-platform/tests/html/canvas/element/layers/2d.layer.malformed-operations-with-promises.createImageBitmap.html34
-rw-r--r--testing/web-platform/tests/html/canvas/element/layers/2d.layer.malformed-operations-with-promises.html40
-rw-r--r--testing/web-platform/tests/html/canvas/element/layers/2d.layer.malformed-operations-with-promises.toBlob.html34
-rw-r--r--testing/web-platform/tests/html/canvas/element/layers/2d.layer.malformed-operations.createPattern.html33
-rw-r--r--testing/web-platform/tests/html/canvas/element/layers/2d.layer.malformed-operations.drawImage.html35
-rw-r--r--testing/web-platform/tests/html/canvas/element/layers/2d.layer.malformed-operations.getImageData.html33
-rw-r--r--testing/web-platform/tests/html/canvas/element/layers/2d.layer.malformed-operations.html87
-rw-r--r--testing/web-platform/tests/html/canvas/element/layers/2d.layer.malformed-operations.putImageData.html36
-rw-r--r--testing/web-platform/tests/html/canvas/element/layers/2d.layer.malformed-operations.toDataURL.html33
-rw-r--r--testing/web-platform/tests/html/canvas/element/manual/filters/svg-filter-lh-rlh-expected.html22
-rw-r--r--testing/web-platform/tests/html/canvas/element/manual/filters/svg-filter-lh-rlh.html32
-rw-r--r--testing/web-platform/tests/html/canvas/element/manual/filters/svg-filter.svg10
-rw-r--r--testing/web-platform/tests/html/canvas/element/text/WEB_FEATURES.yml4
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/fill-and-stroke-styles/2d.fillStyle.parse.hsl-clamp-negative-saturation.html30
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/fill-and-stroke-styles/2d.fillStyle.parse.hsl-clamp-negative-saturation.worker.js25
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/fill-and-stroke-styles/2d.fillStyle.parse.hsla-clamp-alpha-1.html30
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/fill-and-stroke-styles/2d.fillStyle.parse.hsla-clamp-alpha-1.worker.js25
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/fill-and-stroke-styles/2d.fillStyle.parse.hsla-clamp-alpha-2.html30
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/fill-and-stroke-styles/2d.fillStyle.parse.hsla-clamp-alpha-2.worker.js25
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/fill-and-stroke-styles/2d.fillStyle.parse.hsla-clamp-negative-saturation.html30
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/fill-and-stroke-styles/2d.fillStyle.parse.hsla-clamp-negative-saturation.worker.js25
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.gaussianBlur.isotropic.tentative-expected.html15
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.gaussianBlur.isotropic.tentative.html23
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.gaussianBlur.isotropic.tentative.w.html37
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.gaussianBlur.mostly-x.tentative-expected.html15
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.gaussianBlur.mostly-x.tentative.html23
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.gaussianBlur.mostly-x.tentative.w.html37
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.gaussianBlur.mostly-y.tentative-expected.html15
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.gaussianBlur.mostly-y.tentative.html23
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.gaussianBlur.mostly-y.tentative.w.html37
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.gaussianBlur.tentative-expected.html85
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.gaussianBlur.tentative.html121
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.gaussianBlur.tentative.w.html194
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.gaussianBlur.x-only.tentative-expected.html15
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.gaussianBlur.x-only.tentative.html23
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.gaussianBlur.x-only.tentative.w.html37
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.gaussianBlur.y-only.tentative-expected.html15
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.gaussianBlur.y-only.tentative.html23
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.gaussianBlur.y-only.tentative.w.html37
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/filters/2d.filter.layers.gaussianBlur-expected.html85
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/filters/2d.filter.layers.gaussianBlur.html126
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/filters/2d.filter.layers.gaussianBlur.isotropic-expected.html15
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/filters/2d.filter.layers.gaussianBlur.isotropic.html24
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/filters/2d.filter.layers.gaussianBlur.isotropic.w.html38
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/filters/2d.filter.layers.gaussianBlur.mostly-x-expected.html15
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/filters/2d.filter.layers.gaussianBlur.mostly-x.html24
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/filters/2d.filter.layers.gaussianBlur.mostly-x.w.html38
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/filters/2d.filter.layers.gaussianBlur.mostly-y-expected.html15
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/filters/2d.filter.layers.gaussianBlur.mostly-y.html24
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/filters/2d.filter.layers.gaussianBlur.mostly-y.w.html38
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/filters/2d.filter.layers.gaussianBlur.w.html199
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/filters/2d.filter.layers.gaussianBlur.x-only-expected.html15
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/filters/2d.filter.layers.gaussianBlur.x-only.html24
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/filters/2d.filter.layers.gaussianBlur.x-only.w.html38
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/filters/2d.filter.layers.gaussianBlur.y-only-expected.html15
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/filters/2d.filter.layers.gaussianBlur.y-only.html24
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/filters/2d.filter.layers.gaussianBlur.y-only.w.html38
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.beginLayer-options.html11
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.beginLayer-options.worker.js11
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.ctm.getTransform.html11
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.ctm.getTransform.worker.js11
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.exceptions-are-no-op.html11
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.exceptions-are-no-op.worker.js11
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.alpha-expected.html31
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.alpha.blending-expected.html32
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.alpha.blending.html38
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.alpha.blending.shadow-expected.html36
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.alpha.blending.shadow.html42
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.alpha.blending.shadow.w.html56
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.alpha.blending.w.html52
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.alpha.composite-expected.html32
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.alpha.composite.html38
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.alpha.composite.shadow-expected.html36
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.alpha.composite.shadow.html42
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.alpha.composite.shadow.w.html56
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.alpha.composite.w.html52
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.alpha.html37
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.alpha.shadow-expected.html35
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.alpha.shadow.html41
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.alpha.shadow.w.html55
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.alpha.w.html51
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.blending-expected.html31
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.blending.html37
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.blending.no-shadow.no-transform-expected.html72
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.blending.no-shadow.no-transform.html85
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.blending.no-shadow.no-transform.w.html116
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.blending.no-shadow.rotation-expected.html76
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.blending.no-shadow.rotation.html89
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.blending.no-shadow.rotation.w.html120
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.blending.shadow-expected.html35
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.blending.shadow.html41
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.blending.shadow.no-transform-expected.html78
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.blending.shadow.no-transform.html91
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.blending.shadow.no-transform.w.html122
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.blending.shadow.rotation-expected.html82
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.blending.shadow.rotation.html95
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.blending.shadow.rotation.w.html126
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.blending.shadow.w.html55
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.blending.w.html51
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.composite-expected.html31
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.composite.html37
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.composite.no-shadow.no-transform-expected.html72
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.composite.no-shadow.no-transform.html85
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.composite.no-shadow.no-transform.w.html116
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.composite.no-shadow.rotation-expected.html76
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.composite.no-shadow.rotation.html89
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.composite.no-shadow.rotation.w.html120
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.composite.shadow-expected.html35
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.composite.shadow.html41
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.composite.shadow.no-transform-expected.html78
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.composite.shadow.no-transform.html91
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.composite.shadow.no-transform.w.html122
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.composite.shadow.rotation-expected.html82
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.composite.shadow.rotation.html95
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.composite.shadow.rotation.w.html126
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.composite.shadow.w.html55
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.composite.w.html51
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.copy.no-shadow.no-transform-expected.html72
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.copy.no-shadow.no-transform.html85
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.copy.no-shadow.no-transform.w.html116
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.copy.no-shadow.rotation-expected.html76
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.copy.no-shadow.rotation.html89
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.copy.no-shadow.rotation.w.html120
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.copy.shadow.no-transform-expected.html78
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.copy.shadow.no-transform.html91
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.copy.shadow.no-transform.w.html122
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.copy.shadow.rotation-expected.html82
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.copy.shadow.rotation.html95
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.copy.shadow.rotation.w.html126
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.alpha-expected.html50
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.alpha.blending-expected.html51
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.alpha.blending.html42
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.alpha.blending.shadow-expected.html55
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.alpha.blending.shadow.html45
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.alpha.blending.shadow.w.html59
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.alpha.blending.w.html56
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.alpha.composite-expected.html51
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.alpha.composite.html42
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.alpha.composite.shadow-expected.html55
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.alpha.composite.shadow.html45
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.alpha.composite.shadow.w.html59
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.alpha.composite.w.html56
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.alpha.html41
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.alpha.shadow-expected.html54
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.alpha.shadow.html45
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.alpha.shadow.w.html59
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.alpha.w.html55
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.blending-expected.html50
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.blending.html40
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.blending.no-shadow.no-transform-expected.html98
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.blending.no-shadow.no-transform.html85
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.blending.no-shadow.no-transform.w.html116
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.blending.no-shadow.rotation-expected.html102
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.blending.no-shadow.rotation.html89
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.blending.no-shadow.rotation.w.html120
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.blending.shadow-expected.html54
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.blending.shadow.html44
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.blending.shadow.no-transform-expected.html104
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.blending.shadow.no-transform.html91
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.blending.shadow.no-transform.w.html122
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.blending.shadow.rotation-expected.html108
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.blending.shadow.rotation.html95
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.blending.shadow.rotation.w.html126
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.blending.shadow.w.html58
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.blending.w.html54
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.composite-expected.html50
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.composite.html40
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.composite.no-shadow.no-transform-expected.html98
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.composite.no-shadow.no-transform.html85
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.composite.no-shadow.no-transform.w.html116
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.composite.no-shadow.rotation-expected.html102
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.composite.no-shadow.rotation.html89
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.composite.no-shadow.rotation.w.html120
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.composite.shadow-expected.html54
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.composite.shadow.html44
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.composite.shadow.no-transform-expected.html104
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.composite.shadow.no-transform.html91
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.composite.shadow.no-transform.w.html122
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.composite.shadow.rotation-expected.html108
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.composite.shadow.rotation.html95
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.composite.shadow.rotation.w.html126
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.composite.shadow.w.html58
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.composite.w.html54
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.copy.no-shadow.no-transform-expected.html98
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.copy.no-shadow.no-transform.html85
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.copy.no-shadow.no-transform.w.html116
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.copy.no-shadow.rotation-expected.html102
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.copy.no-shadow.rotation.html89
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.copy.no-shadow.rotation.w.html120
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.copy.shadow.no-transform-expected.html104
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.copy.shadow.no-transform.html91
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.copy.shadow.no-transform.w.html122
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.copy.shadow.rotation-expected.html108
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.copy.shadow.rotation.html95
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.copy.shadow.rotation.w.html126
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.no-composite-op.no-shadow.no-transform-expected.html98
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.no-composite-op.no-shadow.no-transform.html85
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.no-composite-op.no-shadow.no-transform.w.html116
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.no-composite-op.no-shadow.rotation-expected.html102
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.no-composite-op.no-shadow.rotation.html89
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.no-composite-op.no-shadow.rotation.w.html120
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.no-composite-op.shadow.no-transform-expected.html104
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.no-composite-op.shadow.no-transform.html91
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.no-composite-op.shadow.no-transform.w.html122
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.no-composite-op.shadow.rotation-expected.html108
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.no-composite-op.shadow.rotation.html95
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.no-composite-op.shadow.rotation.w.html126
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.no-global-states-expected.html50
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.no-global-states.html40
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.no-global-states.w.html54
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.shadow-expected.html53
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.shadow.html43
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.shadow.w.html57
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.no-composite-op.no-shadow.no-transform-expected.html72
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.no-composite-op.no-shadow.no-transform.html85
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.no-composite-op.no-shadow.no-transform.w.html116
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.no-composite-op.no-shadow.rotation-expected.html76
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.no-composite-op.no-shadow.rotation.html89
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.no-composite-op.no-shadow.rotation.w.html120
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.no-composite-op.shadow.no-transform-expected.html78
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.no-composite-op.shadow.no-transform.html91
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.no-composite-op.shadow.no-transform.w.html122
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.no-composite-op.shadow.rotation-expected.html82
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.no-composite-op.shadow.rotation.html95
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.no-composite-op.shadow.rotation.w.html126
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.no-global-states-expected.html31
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.no-global-states.html37
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.no-global-states.w.html51
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.shadow-expected.html34
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.shadow.html40
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.shadow.w.html54
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.globalCompositeOperation-expected.html910
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.globalCompositeOperation.html961
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.globalCompositeOperation.w.html1314
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.invalid-calls.beginLayer-reset-endLayer.html11
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.invalid-calls.beginLayer-reset-endLayer.worker.js11
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.invalid-calls.beginLayer-restore.html11
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.invalid-calls.beginLayer-restore.worker.js11
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.invalid-calls.beginLayer-save-endLayer.html11
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.invalid-calls.beginLayer-save-endLayer.worker.js11
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.invalid-calls.endLayer.html11
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.invalid-calls.endLayer.worker.js11
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.invalid-calls.save-beginLayer-restore.html11
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.invalid-calls.save-beginLayer-restore.worker.js11
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.invalid-calls.save-endLayer.html11
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.invalid-calls.save-endLayer.worker.js11
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.malformed-operations-with-promises.convertToBlob.html27
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.malformed-operations-with-promises.convertToBlob.worker.js21
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.malformed-operations-with-promises.createImageBitmap.html27
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.malformed-operations-with-promises.createImageBitmap.worker.js21
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.malformed-operations-with-promises.html38
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.malformed-operations-with-promises.worker.js37
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.malformed-operations.createPattern.html34
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.malformed-operations.createPattern.worker.js29
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.malformed-operations.drawImage.html36
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.malformed-operations.drawImage.worker.js31
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.malformed-operations.getImageData.html34
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.malformed-operations.getImageData.worker.js29
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.malformed-operations.html85
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.malformed-operations.putImageData.html37
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.malformed-operations.putImageData.worker.js32
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.malformed-operations.transferToImageBitmap.html34
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.malformed-operations.transferToImageBitmap.worker.js29
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.malformed-operations.worker.js84
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/text/WEB_FEATURES.yml4
-rw-r--r--testing/web-platform/tests/html/canvas/tools/gentestutilsunion.py387
-rw-r--r--testing/web-platform/tests/html/canvas/tools/templates/reftest_element.html2
-rw-r--r--testing/web-platform/tests/html/canvas/tools/templates/reftest_element_grid.html56
-rw-r--r--testing/web-platform/tests/html/canvas/tools/templates/reftest_grid.html30
-rw-r--r--testing/web-platform/tests/html/canvas/tools/templates/reftest_offscreen.html2
-rw-r--r--testing/web-platform/tests/html/canvas/tools/templates/reftest_offscreen_grid.html52
-rw-r--r--testing/web-platform/tests/html/canvas/tools/templates/reftest_worker.html2
-rw-r--r--testing/web-platform/tests/html/canvas/tools/templates/reftest_worker_grid.html62
-rw-r--r--testing/web-platform/tests/html/canvas/tools/templates/testharness_element_grid.html52
-rw-r--r--testing/web-platform/tests/html/canvas/tools/templates/testharness_offscreen_grid.html28
-rw-r--r--testing/web-platform/tests/html/canvas/tools/templates/testharness_worker_grid.js27
-rw-r--r--testing/web-platform/tests/html/canvas/tools/yaml-new/filters.yaml8
-rw-r--r--testing/web-platform/tests/html/canvas/tools/yaml-new/layers.yaml292
-rw-r--r--testing/web-platform/tests/html/canvas/tools/yaml/element/meta.yaml14
-rw-r--r--testing/web-platform/tests/html/canvas/tools/yaml/offscreen/meta.yaml14
-rw-r--r--testing/web-platform/tests/html/cross-origin-embedder-policy/META.yml1
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/META.yml1
-rw-r--r--testing/web-platform/tests/html/dom/WEB_FEATURES.yml4
-rw-r--r--testing/web-platform/tests/html/dom/aria-element-reflection.html4
-rw-r--r--testing/web-platform/tests/html/dom/elements/global-attributes/the-anchor-attribute-003.tentative.html4
-rw-r--r--testing/web-platform/tests/html/dom/elements/global-attributes/the-anchor-attribute-xml.tentative.html25
-rw-r--r--testing/web-platform/tests/html/dom/render-blocking/WEB_FEATURES.yml3
-rw-r--r--testing/web-platform/tests/html/dom/usvstring-reflection.https.html2
-rw-r--r--testing/web-platform/tests/html/editing/dnd/events/drag-event-div-manual.html7
-rw-r--r--testing/web-platform/tests/html/editing/dnd/events/drag-event-manual.html7
-rw-r--r--testing/web-platform/tests/html/editing/dnd/events/dragend-event-manual.html7
-rw-r--r--testing/web-platform/tests/html/editing/dnd/events/dragenter-event-manual.html7
-rw-r--r--testing/web-platform/tests/html/editing/dnd/events/dragleave-event-manual.html7
-rw-r--r--testing/web-platform/tests/html/editing/dnd/events/dragover-event-manual.html7
-rw-r--r--testing/web-platform/tests/html/editing/dnd/events/dragstart-event-manual.html7
-rw-r--r--testing/web-platform/tests/html/editing/dnd/events/drop-event-manual.html7
-rw-r--r--testing/web-platform/tests/html/editing/dnd/resources/dragdrop_support.js9
-rw-r--r--testing/web-platform/tests/html/editing/dnd/the-datatransfer-interface/effectAllowed-manual.html9
-rw-r--r--testing/web-platform/tests/html/editing/dnd/the-datatransfer-interface/files-manual.html13
-rw-r--r--testing/web-platform/tests/html/editing/dnd/the-datatransfer-interface/setData-manual.html9
-rw-r--r--testing/web-platform/tests/html/editing/dnd/the-datatransfer-interface/types-manual.html9
-rw-r--r--testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/window-simple-success.https.html1
-rw-r--r--testing/web-platform/tests/html/interaction/focus/WEB_FEATURES.yml4
-rw-r--r--testing/web-platform/tests/html/interaction/focus/sequential-focus-navigation-and-the-tabindex-attribute/WEB_FEATURES.yml3
-rw-r--r--testing/web-platform/tests/html/meta/refresh-time.html53
-rw-r--r--testing/web-platform/tests/html/meta/resources/gotRefreshed.html3
-rw-r--r--testing/web-platform/tests/html/meta/resources/refresh.99.html5
-rw-r--r--testing/web-platform/tests/html/meta/resources/refresh1.99.html5
-rw-r--r--testing/web-platform/tests/html/meta/resources/refresh1.html5
-rw-r--r--testing/web-platform/tests/html/meta/resources/refresh1dotdot5dot.html5
-rw-r--r--testing/web-platform/tests/html/rendering/non-replaced-elements/flow-content-0/WEB_FEATURES.yml4
-rw-r--r--testing/web-platform/tests/html/rendering/replaced-elements/the-select-element/select-1-block-size-001-ref-2.html2
-rw-r--r--testing/web-platform/tests/html/rendering/replaced-elements/the-select-element/select-1-block-size-001-ref.html2
-rw-r--r--testing/web-platform/tests/html/rendering/the-details-element/WEB_FEATURES.yml3
-rw-r--r--testing/web-platform/tests/html/rendering/widgets/input-password-background-suppresses-appearance-ref.html3
-rw-r--r--testing/web-platform/tests/html/rendering/widgets/input-password-background-suppresses-appearance.html7
-rw-r--r--testing/web-platform/tests/html/semantics/embedded-content/media-elements/WEB_FEATURES.yml4
-rw-r--r--testing/web-platform/tests/html/semantics/embedded-content/the-object-element/WEB_FEATURES.yml4
-rw-r--r--testing/web-platform/tests/html/semantics/forms/attributes-common-to-form-controls/WEB_FEATURES.yml4
-rw-r--r--testing/web-platform/tests/html/semantics/forms/constraints/WEB_FEATURES.yml3
-rw-r--r--testing/web-platform/tests/html/semantics/forms/constraints/form-validation-validity-textarea-defaultValue.html98
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-button-element/WEB_FEATURES.yml10
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-fieldset-element/WEB_FEATURES.yml8
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-form-element/WEB_FEATURES.yml4
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-input-element/WEB_FEATURES.yml11
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-input-element/input-stepdown-02.html42
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-output-element/WEB_FEATURES.yml5
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-select-element/WEB_FEATURES.yml9
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-select-element/stylable-select/native-popup-with-datalist-ref.html17
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-select-element/stylable-select/native-popup-with-datalist.tentative.html25
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-select-element/stylable-select/nested-options.tenative.html46
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-select-element/stylable-select/resources/select-reset-non-interoperable-styles.css5
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-select-element/stylable-select/resources/stylable-select-styles.css49
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-select-element/stylable-select/select-appearance-custom-button-no-datalist-ref.html (renamed from testing/web-platform/tests/html/semantics/forms/the-select-element/stylable-select/select-appearance-no-button-custom-datalist-ref.html)2
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-select-element/stylable-select/select-appearance-custom-button-no-datalist.tentative.html3
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-select-element/stylable-select/select-appearance-no-button-custom-datalist.tentative.html3
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-select-element/stylable-select/select-appearance-no-button-no-datalist-ref.html17
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-select-element/stylable-select/select-appearance-no-button-no-datalist.tentative.html3
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-select-element/stylable-select/select-appearance-writing-mode-vertical-lr-ref.html23
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-select-element/stylable-select/select-appearance-writing-mode-vertical-lr.tentative.html29
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-select-element/stylable-select/select-appearance-writing-mode-vertical-rl-ref.html23
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-select-element/stylable-select/select-appearance-writing-mode-vertical-rl.tentative.html29
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-select-element/stylable-select/select-child-button-and-datalist-invalidation.tentative.html1
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-select-element/stylable-select/select-child-button-and-datalist.tentative.html1
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-select-element/stylable-select/select-datalist-popover-behavior.tentative.html75
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-select-element/stylable-select/select-keyboard-behavior.tentative.html14
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-option-arbitrary-content-displayed.tentative.html2
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-textarea-element/WEB_FEATURES.yml6
-rw-r--r--testing/web-platform/tests/html/semantics/interactive-elements/the-details-element/WEB_FEATURES.yml4
-rw-r--r--testing/web-platform/tests/html/semantics/invokers/interesttarget-anchor-event-dispatch.tentative.html47
-rw-r--r--testing/web-platform/tests/html/semantics/invokers/interesttarget-area-event-dispatch.tentative.html50
-rw-r--r--testing/web-platform/tests/html/semantics/invokers/interesttarget-button-event-dispatch.tentative.html31
-rw-r--r--testing/web-platform/tests/html/semantics/invokers/interesttarget-svg-a-event-dispatch.tentative.html51
-rw-r--r--testing/web-platform/tests/html/semantics/invokers/invoketarget-on-input-number.tentative.html78
-rw-r--r--testing/web-platform/tests/html/semantics/permission-element/bounded-css-properties-reftest-ref.html (renamed from testing/web-platform/tests/html/semantics/permission-element/bounded-css-properties-reference-expected.html)0
-rw-r--r--testing/web-platform/tests/html/semantics/permission-element/bounded-css-properties-reftest.tentative.html (renamed from testing/web-platform/tests/html/semantics/permission-element/bounded-css-properties-reference.tentative.html)2
-rw-r--r--testing/web-platform/tests/html/semantics/permission-element/bounded-sizes-reftest-ref.html56
-rw-r--r--testing/web-platform/tests/html/semantics/permission-element/bounded-sizes-reftest.tentative.html68
-rw-r--r--testing/web-platform/tests/html/semantics/permission-element/bounded-sizes.tentative.html75
-rw-r--r--testing/web-platform/tests/html/semantics/permission-element/display-css-property-reftest-ref.html (renamed from testing/web-platform/tests/html/semantics/permission-element/display-css-property-reference-expected.html)0
-rw-r--r--testing/web-platform/tests/html/semantics/permission-element/display-css-property-reftest.tentative.html (renamed from testing/web-platform/tests/html/semantics/permission-element/display-css-property-reference.tentative.html)2
-rw-r--r--testing/web-platform/tests/html/semantics/popovers/popover-anchor-change-display.tentative.html1
-rw-r--r--testing/web-platform/tests/html/semantics/popovers/popover-anchor-display-none.tentative.html1
-rw-r--r--testing/web-platform/tests/html/semantics/popovers/popover-anchor-display.tentative.html1
-rw-r--r--testing/web-platform/tests/html/semantics/popovers/popover-anchor-scroll-display.tentative.html1
-rw-r--r--testing/web-platform/tests/html/semantics/popovers/popover-anchor-transition.tentative.tentative.html1
-rw-r--r--testing/web-platform/tests/html/semantics/popovers/popover-focus-2.html2
-rw-r--r--testing/web-platform/tests/html/semantics/popovers/popover-hover-crash-hang.tentative.html34
-rw-r--r--testing/web-platform/tests/html/semantics/popovers/popover-light-dismiss-scroll-within.html52
-rw-r--r--testing/web-platform/tests/html/semantics/popovers/popover-light-dismiss.html56
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/microtasks/basic.any.js4
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/inline-async-inserted-execorder.html70
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-template-element/WEB_FEATURES.yml3
-rw-r--r--testing/web-platform/tests/html/semantics/selectors/pseudo-classes/WEB_FEATURES.yml11
-rw-r--r--testing/web-platform/tests/html/syntax/parsing/template/WEB_FEATURES.yml3
-rw-r--r--testing/web-platform/tests/html/user-activation/WEB_FEATURES.yml3
-rw-r--r--testing/web-platform/tests/html/webappapis/structured-clone/WEB_FEATURES.yml3
545 files changed, 24218 insertions, 7816 deletions
diff --git a/testing/web-platform/tests/html/browsers/browsing-the-web/scroll-to-fragid/scroll-position-inline-nearest.html b/testing/web-platform/tests/html/browsers/browsing-the-web/scroll-to-fragid/scroll-position-inline-nearest.html
new file mode 100644
index 0000000000..4aab0aa5e5
--- /dev/null
+++ b/testing/web-platform/tests/html/browsers/browsing-the-web/scroll-to-fragid/scroll-position-inline-nearest.html
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<html style="writing-mode: vertical-lr;">
+<head>
+<meta charset="UTF-8">
+<title>Fragment Navigation: inline start position should not scroll out of content range</title>
+<link rel="help" href="https://html.spec.whatwg.org/multipage/#scroll-to-the-fragment-identifier">
+<link rel="author" href="mailto:mrobinson@igalia.com" title="Martin Robinson">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+</head>
+<body>
+ <!-- When scrolling to this fragment the viewport inline position should not
+ change because, it is already fully enclosed by the viewport and page width. -->
+ <div id="test1" style="position: absolute; top: 5000px; left: 100px; height: 100px; width: 100px;"></div>
+<script>
+
+var t = async_test("ScrollToFragment");
+t.step(() => {
+ location.hash = "test1";
+ setTimeout(t.step_func(() => {
+ assert_true(window.scrollY > 0);
+ assert_true(window.scrollY < 5000);
+ assert_equals(window.scrollX, 0);
+ t.done();
+ }));
+});
+
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/html/canvas/element/fill-and-stroke-styles/2d.fillStyle.parse.hsl-clamp-1.html b/testing/web-platform/tests/html/canvas/element/fill-and-stroke-styles/2d.fillStyle.parse.hsl-clamp-1.html
deleted file mode 100644
index 59d66c383c..0000000000
--- a/testing/web-platform/tests/html/canvas/element/fill-and-stroke-styles/2d.fillStyle.parse.hsl-clamp-1.html
+++ /dev/null
@@ -1,29 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<title>Canvas test: 2d.fillStyle.parse.hsl-clamp-1</title>
-<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">
-<body class="show_output">
-
-<h1>2d.fillStyle.parse.hsl-clamp-1</h1>
-<p class="desc"></p>
-
-<p class="notes">
-<p class="output">Actual output:</p>
-<canvas id="c" class="output" width="100" height="50"><p class="fallback">FAIL (fallback content)</p></canvas>
-<p class="output expectedtext">Expected output:<p><img src="2d.fillStyle.parse.hsl-clamp-1.png" class="output expected" id="expected" alt="">
-<ul id="d"></ul>
-<script>
-var t = async_test("");
-_addTest(function(canvas, ctx) {
-
- ctx.fillStyle = '#f00';
- ctx.fillStyle = 'hsl(120, 200%, 50%)';
- ctx.fillRect(0, 0, 100, 50);
- _assertPixel(canvas, 50,25, 0,255,0,255);
-
-});
-</script>
-
diff --git a/testing/web-platform/tests/html/canvas/element/fill-and-stroke-styles/2d.fillStyle.parse.hsl-clamp-3.html b/testing/web-platform/tests/html/canvas/element/fill-and-stroke-styles/2d.fillStyle.parse.hsl-clamp-3.html
deleted file mode 100644
index 56f3a0a8b5..0000000000
--- a/testing/web-platform/tests/html/canvas/element/fill-and-stroke-styles/2d.fillStyle.parse.hsl-clamp-3.html
+++ /dev/null
@@ -1,29 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<title>Canvas test: 2d.fillStyle.parse.hsl-clamp-3</title>
-<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">
-<body class="show_output">
-
-<h1>2d.fillStyle.parse.hsl-clamp-3</h1>
-<p class="desc"></p>
-
-<p class="notes">
-<p class="output">Actual output:</p>
-<canvas id="c" class="output" width="100" height="50"><p class="fallback">FAIL (fallback content)</p></canvas>
-<p class="output expectedtext">Expected output:<p><img src="2d.fillStyle.parse.hsl-clamp-3.png" class="output expected" id="expected" alt="">
-<ul id="d"></ul>
-<script>
-var t = async_test("");
-_addTest(function(canvas, ctx) {
-
- ctx.fillStyle = '#f00';
- ctx.fillStyle = 'hsl(120, 100%, 200%)';
- ctx.fillRect(0, 0, 100, 50);
- _assertPixel(canvas, 50,25, 255,255,255,255);
-
-});
-</script>
-
diff --git a/testing/web-platform/tests/html/canvas/element/fill-and-stroke-styles/2d.fillStyle.parse.hsl-clamp-3.png b/testing/web-platform/tests/html/canvas/element/fill-and-stroke-styles/2d.fillStyle.parse.hsl-clamp-3.png
deleted file mode 100644
index bf48767a88..0000000000
--- a/testing/web-platform/tests/html/canvas/element/fill-and-stroke-styles/2d.fillStyle.parse.hsl-clamp-3.png
+++ /dev/null
Binary files differ
diff --git a/testing/web-platform/tests/html/canvas/element/fill-and-stroke-styles/2d.fillStyle.parse.hsl-clamp-4.html b/testing/web-platform/tests/html/canvas/element/fill-and-stroke-styles/2d.fillStyle.parse.hsl-clamp-4.html
deleted file mode 100644
index af9d11e678..0000000000
--- a/testing/web-platform/tests/html/canvas/element/fill-and-stroke-styles/2d.fillStyle.parse.hsl-clamp-4.html
+++ /dev/null
@@ -1,29 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<title>Canvas test: 2d.fillStyle.parse.hsl-clamp-4</title>
-<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">
-<body class="show_output">
-
-<h1>2d.fillStyle.parse.hsl-clamp-4</h1>
-<p class="desc"></p>
-
-<p class="notes">
-<p class="output">Actual output:</p>
-<canvas id="c" class="output" width="100" height="50"><p class="fallback">FAIL (fallback content)</p></canvas>
-<p class="output expectedtext">Expected output:<p><img src="2d.fillStyle.parse.hsl-clamp-4.png" class="output expected" id="expected" alt="">
-<ul id="d"></ul>
-<script>
-var t = async_test("");
-_addTest(function(canvas, ctx) {
-
- ctx.fillStyle = '#f00';
- ctx.fillStyle = 'hsl(120, 100%, -200%)';
- ctx.fillRect(0, 0, 100, 50);
- _assertPixel(canvas, 50,25, 0,0,0,255);
-
-});
-</script>
-
diff --git a/testing/web-platform/tests/html/canvas/element/fill-and-stroke-styles/2d.fillStyle.parse.hsl-clamp-4.png b/testing/web-platform/tests/html/canvas/element/fill-and-stroke-styles/2d.fillStyle.parse.hsl-clamp-4.png
deleted file mode 100644
index d638d03386..0000000000
--- a/testing/web-platform/tests/html/canvas/element/fill-and-stroke-styles/2d.fillStyle.parse.hsl-clamp-4.png
+++ /dev/null
Binary files differ
diff --git a/testing/web-platform/tests/html/canvas/element/fill-and-stroke-styles/2d.fillStyle.parse.hsl-clamp-2.html b/testing/web-platform/tests/html/canvas/element/fill-and-stroke-styles/2d.fillStyle.parse.hsl-clamp-negative-saturation.html
index 1a1939e47a..65440c6228 100644
--- a/testing/web-platform/tests/html/canvas/element/fill-and-stroke-styles/2d.fillStyle.parse.hsl-clamp-2.html
+++ b/testing/web-platform/tests/html/canvas/element/fill-and-stroke-styles/2d.fillStyle.parse.hsl-clamp-negative-saturation.html
@@ -1,19 +1,19 @@
<!DOCTYPE html>
<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<title>Canvas test: 2d.fillStyle.parse.hsl-clamp-2</title>
+<title>Canvas test: 2d.fillStyle.parse.hsl-clamp-negative-saturation</title>
<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">
<body class="show_output">
-<h1>2d.fillStyle.parse.hsl-clamp-2</h1>
+<h1>2d.fillStyle.parse.hsl-clamp-negative-saturation</h1>
<p class="desc"></p>
<p class="notes">
<p class="output">Actual output:</p>
<canvas id="c" class="output" width="100" height="50"><p class="fallback">FAIL (fallback content)</p></canvas>
-<p class="output expectedtext">Expected output:<p><img src="2d.fillStyle.parse.hsl-clamp-2.png" class="output expected" id="expected" alt="">
+<p class="output expectedtext">Expected output:<p><img src="2d.fillStyle.parse.hsl-clamp-negative-saturation.png" class="output expected" id="expected" alt="">
<ul id="d"></ul>
<script>
var t = async_test("");
diff --git a/testing/web-platform/tests/html/canvas/element/fill-and-stroke-styles/2d.fillStyle.parse.hsl-clamp-2.png b/testing/web-platform/tests/html/canvas/element/fill-and-stroke-styles/2d.fillStyle.parse.hsl-clamp-negative-saturation.png
index 88fd827985..88fd827985 100644
--- a/testing/web-platform/tests/html/canvas/element/fill-and-stroke-styles/2d.fillStyle.parse.hsl-clamp-2.png
+++ b/testing/web-platform/tests/html/canvas/element/fill-and-stroke-styles/2d.fillStyle.parse.hsl-clamp-negative-saturation.png
Binary files differ
diff --git a/testing/web-platform/tests/html/canvas/element/fill-and-stroke-styles/2d.fillStyle.parse.hsla-clamp-1.html b/testing/web-platform/tests/html/canvas/element/fill-and-stroke-styles/2d.fillStyle.parse.hsla-clamp-1.html
deleted file mode 100644
index 2acac26e1a..0000000000
--- a/testing/web-platform/tests/html/canvas/element/fill-and-stroke-styles/2d.fillStyle.parse.hsla-clamp-1.html
+++ /dev/null
@@ -1,29 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<title>Canvas test: 2d.fillStyle.parse.hsla-clamp-1</title>
-<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">
-<body class="show_output">
-
-<h1>2d.fillStyle.parse.hsla-clamp-1</h1>
-<p class="desc"></p>
-
-<p class="notes">
-<p class="output">Actual output:</p>
-<canvas id="c" class="output" width="100" height="50"><p class="fallback">FAIL (fallback content)</p></canvas>
-<p class="output expectedtext">Expected output:<p><img src="2d.fillStyle.parse.hsla-clamp-1.png" class="output expected" id="expected" alt="">
-<ul id="d"></ul>
-<script>
-var t = async_test("");
-_addTest(function(canvas, ctx) {
-
- ctx.fillStyle = '#f00';
- ctx.fillStyle = 'hsla(120, 200%, 50%, 1)';
- ctx.fillRect(0, 0, 100, 50);
- _assertPixel(canvas, 50,25, 0,255,0,255);
-
-});
-</script>
-
diff --git a/testing/web-platform/tests/html/canvas/element/fill-and-stroke-styles/2d.fillStyle.parse.hsla-clamp-1.png b/testing/web-platform/tests/html/canvas/element/fill-and-stroke-styles/2d.fillStyle.parse.hsla-clamp-1.png
deleted file mode 100644
index 2733836c99..0000000000
--- a/testing/web-platform/tests/html/canvas/element/fill-and-stroke-styles/2d.fillStyle.parse.hsla-clamp-1.png
+++ /dev/null
Binary files differ
diff --git a/testing/web-platform/tests/html/canvas/element/fill-and-stroke-styles/2d.fillStyle.parse.hsla-clamp-3.html b/testing/web-platform/tests/html/canvas/element/fill-and-stroke-styles/2d.fillStyle.parse.hsla-clamp-3.html
deleted file mode 100644
index 4bc134aec5..0000000000
--- a/testing/web-platform/tests/html/canvas/element/fill-and-stroke-styles/2d.fillStyle.parse.hsla-clamp-3.html
+++ /dev/null
@@ -1,29 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<title>Canvas test: 2d.fillStyle.parse.hsla-clamp-3</title>
-<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">
-<body class="show_output">
-
-<h1>2d.fillStyle.parse.hsla-clamp-3</h1>
-<p class="desc"></p>
-
-<p class="notes">
-<p class="output">Actual output:</p>
-<canvas id="c" class="output" width="100" height="50"><p class="fallback">FAIL (fallback content)</p></canvas>
-<p class="output expectedtext">Expected output:<p><img src="2d.fillStyle.parse.hsla-clamp-3.png" class="output expected" id="expected" alt="">
-<ul id="d"></ul>
-<script>
-var t = async_test("");
-_addTest(function(canvas, ctx) {
-
- ctx.fillStyle = '#f00';
- ctx.fillStyle = 'hsla(120, 100%, 200%, 1)';
- ctx.fillRect(0, 0, 100, 50);
- _assertPixel(canvas, 50,25, 255,255,255,255);
-
-});
-</script>
-
diff --git a/testing/web-platform/tests/html/canvas/element/fill-and-stroke-styles/2d.fillStyle.parse.hsla-clamp-3.png b/testing/web-platform/tests/html/canvas/element/fill-and-stroke-styles/2d.fillStyle.parse.hsla-clamp-3.png
deleted file mode 100644
index bf48767a88..0000000000
--- a/testing/web-platform/tests/html/canvas/element/fill-and-stroke-styles/2d.fillStyle.parse.hsla-clamp-3.png
+++ /dev/null
Binary files differ
diff --git a/testing/web-platform/tests/html/canvas/element/fill-and-stroke-styles/2d.fillStyle.parse.hsla-clamp-4.html b/testing/web-platform/tests/html/canvas/element/fill-and-stroke-styles/2d.fillStyle.parse.hsla-clamp-4.html
deleted file mode 100644
index f8b2382755..0000000000
--- a/testing/web-platform/tests/html/canvas/element/fill-and-stroke-styles/2d.fillStyle.parse.hsla-clamp-4.html
+++ /dev/null
@@ -1,29 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<title>Canvas test: 2d.fillStyle.parse.hsla-clamp-4</title>
-<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">
-<body class="show_output">
-
-<h1>2d.fillStyle.parse.hsla-clamp-4</h1>
-<p class="desc"></p>
-
-<p class="notes">
-<p class="output">Actual output:</p>
-<canvas id="c" class="output" width="100" height="50"><p class="fallback">FAIL (fallback content)</p></canvas>
-<p class="output expectedtext">Expected output:<p><img src="2d.fillStyle.parse.hsla-clamp-4.png" class="output expected" id="expected" alt="">
-<ul id="d"></ul>
-<script>
-var t = async_test("");
-_addTest(function(canvas, ctx) {
-
- ctx.fillStyle = '#f00';
- ctx.fillStyle = 'hsla(120, 100%, -200%, 1)';
- ctx.fillRect(0, 0, 100, 50);
- _assertPixel(canvas, 50,25, 0,0,0,255);
-
-});
-</script>
-
diff --git a/testing/web-platform/tests/html/canvas/element/fill-and-stroke-styles/2d.fillStyle.parse.hsla-clamp-4.png b/testing/web-platform/tests/html/canvas/element/fill-and-stroke-styles/2d.fillStyle.parse.hsla-clamp-4.png
deleted file mode 100644
index d638d03386..0000000000
--- a/testing/web-platform/tests/html/canvas/element/fill-and-stroke-styles/2d.fillStyle.parse.hsla-clamp-4.png
+++ /dev/null
Binary files differ
diff --git a/testing/web-platform/tests/html/canvas/element/fill-and-stroke-styles/2d.fillStyle.parse.hsla-clamp-5.png b/testing/web-platform/tests/html/canvas/element/fill-and-stroke-styles/2d.fillStyle.parse.hsla-clamp-5.png
deleted file mode 100644
index 2733836c99..0000000000
--- a/testing/web-platform/tests/html/canvas/element/fill-and-stroke-styles/2d.fillStyle.parse.hsla-clamp-5.png
+++ /dev/null
Binary files differ
diff --git a/testing/web-platform/tests/html/canvas/element/fill-and-stroke-styles/2d.fillStyle.parse.hsla-clamp-5.html b/testing/web-platform/tests/html/canvas/element/fill-and-stroke-styles/2d.fillStyle.parse.hsla-clamp-alpha-1.html
index 9c5e2258b9..e5dc98d4e3 100644
--- a/testing/web-platform/tests/html/canvas/element/fill-and-stroke-styles/2d.fillStyle.parse.hsla-clamp-5.html
+++ b/testing/web-platform/tests/html/canvas/element/fill-and-stroke-styles/2d.fillStyle.parse.hsla-clamp-alpha-1.html
@@ -1,19 +1,19 @@
<!DOCTYPE html>
<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<title>Canvas test: 2d.fillStyle.parse.hsla-clamp-5</title>
+<title>Canvas test: 2d.fillStyle.parse.hsla-clamp-alpha-1</title>
<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">
<body class="show_output">
-<h1>2d.fillStyle.parse.hsla-clamp-5</h1>
+<h1>2d.fillStyle.parse.hsla-clamp-alpha-1</h1>
<p class="desc"></p>
<p class="notes">
<p class="output">Actual output:</p>
<canvas id="c" class="output" width="100" height="50"><p class="fallback">FAIL (fallback content)</p></canvas>
-<p class="output expectedtext">Expected output:<p><img src="2d.fillStyle.parse.hsla-clamp-5.png" class="output expected" id="expected" alt="">
+<p class="output expectedtext">Expected output:<p><img src="2d.fillStyle.parse.hsla-clamp-alpha-1.png" class="output expected" id="expected" alt="">
<ul id="d"></ul>
<script>
var t = async_test("");
diff --git a/testing/web-platform/tests/html/canvas/element/fill-and-stroke-styles/2d.fillStyle.parse.hsl-clamp-1.png b/testing/web-platform/tests/html/canvas/element/fill-and-stroke-styles/2d.fillStyle.parse.hsla-clamp-alpha-1.png
index 2733836c99..2733836c99 100644
--- a/testing/web-platform/tests/html/canvas/element/fill-and-stroke-styles/2d.fillStyle.parse.hsl-clamp-1.png
+++ b/testing/web-platform/tests/html/canvas/element/fill-and-stroke-styles/2d.fillStyle.parse.hsla-clamp-alpha-1.png
Binary files differ
diff --git a/testing/web-platform/tests/html/canvas/element/fill-and-stroke-styles/2d.fillStyle.parse.hsla-clamp-6.html b/testing/web-platform/tests/html/canvas/element/fill-and-stroke-styles/2d.fillStyle.parse.hsla-clamp-alpha-2.html
index 153515eedd..26139a562e 100644
--- a/testing/web-platform/tests/html/canvas/element/fill-and-stroke-styles/2d.fillStyle.parse.hsla-clamp-6.html
+++ b/testing/web-platform/tests/html/canvas/element/fill-and-stroke-styles/2d.fillStyle.parse.hsla-clamp-alpha-2.html
@@ -1,19 +1,19 @@
<!DOCTYPE html>
<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<title>Canvas test: 2d.fillStyle.parse.hsla-clamp-6</title>
+<title>Canvas test: 2d.fillStyle.parse.hsla-clamp-alpha-2</title>
<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">
<body class="show_output">
-<h1>2d.fillStyle.parse.hsla-clamp-6</h1>
+<h1>2d.fillStyle.parse.hsla-clamp-alpha-2</h1>
<p class="desc"></p>
<p class="notes">
<p class="output">Actual output:</p>
<canvas id="c" class="output" width="100" height="50"><p class="fallback">FAIL (fallback content)</p></canvas>
-<p class="output expectedtext">Expected output:<p><img src="2d.fillStyle.parse.hsla-clamp-6.png" class="output expected" id="expected" alt="">
+<p class="output expectedtext">Expected output:<p><img src="2d.fillStyle.parse.hsla-clamp-alpha-2.png" class="output expected" id="expected" alt="">
<ul id="d"></ul>
<script>
var t = async_test("");
diff --git a/testing/web-platform/tests/html/canvas/element/fill-and-stroke-styles/2d.fillStyle.parse.hsla-clamp-6.png b/testing/web-platform/tests/html/canvas/element/fill-and-stroke-styles/2d.fillStyle.parse.hsla-clamp-alpha-2.png
index eeedd0ff05..eeedd0ff05 100644
--- a/testing/web-platform/tests/html/canvas/element/fill-and-stroke-styles/2d.fillStyle.parse.hsla-clamp-6.png
+++ b/testing/web-platform/tests/html/canvas/element/fill-and-stroke-styles/2d.fillStyle.parse.hsla-clamp-alpha-2.png
Binary files differ
diff --git a/testing/web-platform/tests/html/canvas/element/fill-and-stroke-styles/2d.fillStyle.parse.hsla-clamp-2.html b/testing/web-platform/tests/html/canvas/element/fill-and-stroke-styles/2d.fillStyle.parse.hsla-clamp-negative-saturation.html
index 0f32fb5474..2d9b9d3bdf 100644
--- a/testing/web-platform/tests/html/canvas/element/fill-and-stroke-styles/2d.fillStyle.parse.hsla-clamp-2.html
+++ b/testing/web-platform/tests/html/canvas/element/fill-and-stroke-styles/2d.fillStyle.parse.hsla-clamp-negative-saturation.html
@@ -1,19 +1,19 @@
<!DOCTYPE html>
<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<title>Canvas test: 2d.fillStyle.parse.hsla-clamp-2</title>
+<title>Canvas test: 2d.fillStyle.parse.hsla-clamp-negative-saturation</title>
<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">
<body class="show_output">
-<h1>2d.fillStyle.parse.hsla-clamp-2</h1>
+<h1>2d.fillStyle.parse.hsla-clamp-negative-saturation</h1>
<p class="desc"></p>
<p class="notes">
<p class="output">Actual output:</p>
<canvas id="c" class="output" width="100" height="50"><p class="fallback">FAIL (fallback content)</p></canvas>
-<p class="output expectedtext">Expected output:<p><img src="2d.fillStyle.parse.hsla-clamp-2.png" class="output expected" id="expected" alt="">
+<p class="output expectedtext">Expected output:<p><img src="2d.fillStyle.parse.hsla-clamp-negative-saturation.png" class="output expected" id="expected" alt="">
<ul id="d"></ul>
<script>
var t = async_test("");
diff --git a/testing/web-platform/tests/html/canvas/element/fill-and-stroke-styles/2d.fillStyle.parse.hsla-clamp-2.png b/testing/web-platform/tests/html/canvas/element/fill-and-stroke-styles/2d.fillStyle.parse.hsla-clamp-negative-saturation.png
index 88fd827985..88fd827985 100644
--- a/testing/web-platform/tests/html/canvas/element/fill-and-stroke-styles/2d.fillStyle.parse.hsla-clamp-2.png
+++ b/testing/web-platform/tests/html/canvas/element/fill-and-stroke-styles/2d.fillStyle.parse.hsla-clamp-negative-saturation.png
Binary files differ
diff --git a/testing/web-platform/tests/html/canvas/element/filters/2d.filter.canvasFilterObject.gaussianBlur.isotropic.tentative-expected.html b/testing/web-platform/tests/html/canvas/element/filters/2d.filter.canvasFilterObject.gaussianBlur.isotropic.tentative-expected.html
deleted file mode 100644
index dac31c97f1..0000000000
--- a/testing/web-platform/tests/html/canvas/element/filters/2d.filter.canvasFilterObject.gaussianBlur.isotropic.tentative-expected.html
+++ /dev/null
@@ -1,15 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<title>Canvas test: 2d.filter.canvasFilterObject.gaussianBlur.isotropic.tentative</title>
-<h1>2d.filter.canvasFilterObject.gaussianBlur.isotropic.tentative</h1>
-<p class="desc">Test CanvasFilter() with gaussianBlur.</p>
-
-<svg xmlns="http://www.w3.org/2000/svg"
- width="100" height="100"
- color-interpolation-filters="sRGB">
- <filter id="blur" x="-50%" y="-50%" width="200%" height="200%">
- <feGaussianBlur stdDeviation="4 4" />
- </filter>
- <rect x="25" y="25" width="50" height="50"
- fill="teal" filter="url(#blur)" />
-</svg>
diff --git a/testing/web-platform/tests/html/canvas/element/filters/2d.filter.canvasFilterObject.gaussianBlur.isotropic.tentative.html b/testing/web-platform/tests/html/canvas/element/filters/2d.filter.canvasFilterObject.gaussianBlur.isotropic.tentative.html
deleted file mode 100644
index f4c8c1033a..0000000000
--- a/testing/web-platform/tests/html/canvas/element/filters/2d.filter.canvasFilterObject.gaussianBlur.isotropic.tentative.html
+++ /dev/null
@@ -1,20 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<link rel="match" href="2d.filter.canvasFilterObject.gaussianBlur.isotropic.tentative-expected.html">
-<title>Canvas test: 2d.filter.canvasFilterObject.gaussianBlur.isotropic.tentative</title>
-<h1>2d.filter.canvasFilterObject.gaussianBlur.isotropic.tentative</h1>
-<p class="desc">Test CanvasFilter() with gaussianBlur.</p>
-<canvas id="canvas" width="100" height="100">
- <p class="fallback">FAIL (fallback content)</p>
-</canvas>
-<script>
- const canvas = document.getElementById("canvas");
- const ctx = canvas.getContext('2d');
-
- ctx.fillStyle = 'teal';
- ctx.filter = new CanvasFilter({
- name: 'gaussianBlur',
- stdDeviation: [4, 4],
- });
- ctx.fillRect(25, 25, 50, 50);
-</script>
diff --git a/testing/web-platform/tests/html/canvas/element/filters/2d.filter.canvasFilterObject.gaussianBlur.mostly-x.tentative-expected.html b/testing/web-platform/tests/html/canvas/element/filters/2d.filter.canvasFilterObject.gaussianBlur.mostly-x.tentative-expected.html
deleted file mode 100644
index 88d0cb2de2..0000000000
--- a/testing/web-platform/tests/html/canvas/element/filters/2d.filter.canvasFilterObject.gaussianBlur.mostly-x.tentative-expected.html
+++ /dev/null
@@ -1,15 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<title>Canvas test: 2d.filter.canvasFilterObject.gaussianBlur.mostly-x.tentative</title>
-<h1>2d.filter.canvasFilterObject.gaussianBlur.mostly-x.tentative</h1>
-<p class="desc">Test CanvasFilter() with gaussianBlur.</p>
-
-<svg xmlns="http://www.w3.org/2000/svg"
- width="100" height="100"
- color-interpolation-filters="sRGB">
- <filter id="blur" x="-50%" y="-50%" width="200%" height="200%">
- <feGaussianBlur stdDeviation="4 1" />
- </filter>
- <rect x="25" y="25" width="50" height="50"
- fill="teal" filter="url(#blur)" />
-</svg>
diff --git a/testing/web-platform/tests/html/canvas/element/filters/2d.filter.canvasFilterObject.gaussianBlur.mostly-x.tentative.html b/testing/web-platform/tests/html/canvas/element/filters/2d.filter.canvasFilterObject.gaussianBlur.mostly-x.tentative.html
deleted file mode 100644
index b3efcb8c3e..0000000000
--- a/testing/web-platform/tests/html/canvas/element/filters/2d.filter.canvasFilterObject.gaussianBlur.mostly-x.tentative.html
+++ /dev/null
@@ -1,20 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<link rel="match" href="2d.filter.canvasFilterObject.gaussianBlur.mostly-x.tentative-expected.html">
-<title>Canvas test: 2d.filter.canvasFilterObject.gaussianBlur.mostly-x.tentative</title>
-<h1>2d.filter.canvasFilterObject.gaussianBlur.mostly-x.tentative</h1>
-<p class="desc">Test CanvasFilter() with gaussianBlur.</p>
-<canvas id="canvas" width="100" height="100">
- <p class="fallback">FAIL (fallback content)</p>
-</canvas>
-<script>
- const canvas = document.getElementById("canvas");
- const ctx = canvas.getContext('2d');
-
- ctx.fillStyle = 'teal';
- ctx.filter = new CanvasFilter({
- name: 'gaussianBlur',
- stdDeviation: [4, 1],
- });
- ctx.fillRect(25, 25, 50, 50);
-</script>
diff --git a/testing/web-platform/tests/html/canvas/element/filters/2d.filter.canvasFilterObject.gaussianBlur.mostly-y.tentative-expected.html b/testing/web-platform/tests/html/canvas/element/filters/2d.filter.canvasFilterObject.gaussianBlur.mostly-y.tentative-expected.html
deleted file mode 100644
index 744983d4ae..0000000000
--- a/testing/web-platform/tests/html/canvas/element/filters/2d.filter.canvasFilterObject.gaussianBlur.mostly-y.tentative-expected.html
+++ /dev/null
@@ -1,15 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<title>Canvas test: 2d.filter.canvasFilterObject.gaussianBlur.mostly-y.tentative</title>
-<h1>2d.filter.canvasFilterObject.gaussianBlur.mostly-y.tentative</h1>
-<p class="desc">Test CanvasFilter() with gaussianBlur.</p>
-
-<svg xmlns="http://www.w3.org/2000/svg"
- width="100" height="100"
- color-interpolation-filters="sRGB">
- <filter id="blur" x="-50%" y="-50%" width="200%" height="200%">
- <feGaussianBlur stdDeviation="1 4" />
- </filter>
- <rect x="25" y="25" width="50" height="50"
- fill="teal" filter="url(#blur)" />
-</svg>
diff --git a/testing/web-platform/tests/html/canvas/element/filters/2d.filter.canvasFilterObject.gaussianBlur.mostly-y.tentative.html b/testing/web-platform/tests/html/canvas/element/filters/2d.filter.canvasFilterObject.gaussianBlur.mostly-y.tentative.html
deleted file mode 100644
index d5cc6e0058..0000000000
--- a/testing/web-platform/tests/html/canvas/element/filters/2d.filter.canvasFilterObject.gaussianBlur.mostly-y.tentative.html
+++ /dev/null
@@ -1,20 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<link rel="match" href="2d.filter.canvasFilterObject.gaussianBlur.mostly-y.tentative-expected.html">
-<title>Canvas test: 2d.filter.canvasFilterObject.gaussianBlur.mostly-y.tentative</title>
-<h1>2d.filter.canvasFilterObject.gaussianBlur.mostly-y.tentative</h1>
-<p class="desc">Test CanvasFilter() with gaussianBlur.</p>
-<canvas id="canvas" width="100" height="100">
- <p class="fallback">FAIL (fallback content)</p>
-</canvas>
-<script>
- const canvas = document.getElementById("canvas");
- const ctx = canvas.getContext('2d');
-
- ctx.fillStyle = 'teal';
- ctx.filter = new CanvasFilter({
- name: 'gaussianBlur',
- stdDeviation: [1, 4],
- });
- ctx.fillRect(25, 25, 50, 50);
-</script>
diff --git a/testing/web-platform/tests/html/canvas/element/filters/2d.filter.canvasFilterObject.gaussianBlur.tentative-expected.html b/testing/web-platform/tests/html/canvas/element/filters/2d.filter.canvasFilterObject.gaussianBlur.tentative-expected.html
new file mode 100644
index 0000000000..c1ca0ab46f
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/element/filters/2d.filter.canvasFilterObject.gaussianBlur.tentative-expected.html
@@ -0,0 +1,85 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<title>Canvas test: 2d.filter.canvasFilterObject.gaussianBlur.tentative</title>
+<h1 style="font-size: 20px;">2d.filter.canvasFilterObject.gaussianBlur.tentative</h1>
+<p class="desc">Test CanvasFilter() with gaussianBlur.</p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(5, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>x-only</div>
+ <div style="width: 100px; height: 100px; outline: 1px solid">
+ <svg xmlns="http://www.w3.org/2000/svg"
+ width="100" height="100"
+ color-interpolation-filters="sRGB">
+ <filter id="blur0" x="-50%" y="-50%" width="200%" height="200%">
+ <feGaussianBlur stdDeviation="4 0" />
+ </filter>
+ <rect x="25" y="25" width="50" height="50"
+ fill="teal" filter="url(#blur0)" />
+ </svg>
+ </div>
+</span>
+
+<span>
+ <div>mostly-x</div>
+ <div style="width: 100px; height: 100px; outline: 1px solid">
+ <svg xmlns="http://www.w3.org/2000/svg"
+ width="100" height="100"
+ color-interpolation-filters="sRGB">
+ <filter id="blur1" x="-50%" y="-50%" width="200%" height="200%">
+ <feGaussianBlur stdDeviation="4 1" />
+ </filter>
+ <rect x="25" y="25" width="50" height="50"
+ fill="teal" filter="url(#blur1)" />
+ </svg>
+ </div>
+</span>
+
+<span>
+ <div>isotropic</div>
+ <div style="width: 100px; height: 100px; outline: 1px solid">
+ <svg xmlns="http://www.w3.org/2000/svg"
+ width="100" height="100"
+ color-interpolation-filters="sRGB">
+ <filter id="blur2" x="-50%" y="-50%" width="200%" height="200%">
+ <feGaussianBlur stdDeviation="4 4" />
+ </filter>
+ <rect x="25" y="25" width="50" height="50"
+ fill="teal" filter="url(#blur2)" />
+ </svg>
+ </div>
+</span>
+
+<span>
+ <div>mostly-y</div>
+ <div style="width: 100px; height: 100px; outline: 1px solid">
+ <svg xmlns="http://www.w3.org/2000/svg"
+ width="100" height="100"
+ color-interpolation-filters="sRGB">
+ <filter id="blur3" x="-50%" y="-50%" width="200%" height="200%">
+ <feGaussianBlur stdDeviation="1 4" />
+ </filter>
+ <rect x="25" y="25" width="50" height="50"
+ fill="teal" filter="url(#blur3)" />
+ </svg>
+ </div>
+</span>
+
+<span>
+ <div>y-only</div>
+ <div style="width: 100px; height: 100px; outline: 1px solid">
+ <svg xmlns="http://www.w3.org/2000/svg"
+ width="100" height="100"
+ color-interpolation-filters="sRGB">
+ <filter id="blur4" x="-50%" y="-50%" width="200%" height="200%">
+ <feGaussianBlur stdDeviation="0 4" />
+ </filter>
+ <rect x="25" y="25" width="50" height="50"
+ fill="teal" filter="url(#blur4)" />
+ </svg>
+ </div>
+</span>
+
+</div>
diff --git a/testing/web-platform/tests/html/canvas/element/filters/2d.filter.canvasFilterObject.gaussianBlur.tentative.html b/testing/web-platform/tests/html/canvas/element/filters/2d.filter.canvasFilterObject.gaussianBlur.tentative.html
new file mode 100644
index 0000000000..498418c292
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/element/filters/2d.filter.canvasFilterObject.gaussianBlur.tentative.html
@@ -0,0 +1,101 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<link rel="match" href="2d.filter.canvasFilterObject.gaussianBlur.tentative-expected.html">
+<title>Canvas test: 2d.filter.canvasFilterObject.gaussianBlur.tentative</title>
+<h1 style="font-size: 20px;">2d.filter.canvasFilterObject.gaussianBlur.tentative</h1>
+<p class="desc">Test CanvasFilter() with gaussianBlur.</p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(5, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>x-only</div>
+ <canvas id="canvas0" width="100" height="100" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas0");
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'teal';
+ ctx.filter = new CanvasFilter({
+ name: 'gaussianBlur',
+ stdDeviation: [4, 0],
+ });
+ ctx.fillRect(25, 25, 50, 50);
+ </script>
+</span>
+
+<span>
+ <div>mostly-x</div>
+ <canvas id="canvas1" width="100" height="100" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas1");
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'teal';
+ ctx.filter = new CanvasFilter({
+ name: 'gaussianBlur',
+ stdDeviation: [4, 1],
+ });
+ ctx.fillRect(25, 25, 50, 50);
+ </script>
+</span>
+
+<span>
+ <div>isotropic</div>
+ <canvas id="canvas2" width="100" height="100" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas2");
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'teal';
+ ctx.filter = new CanvasFilter({
+ name: 'gaussianBlur',
+ stdDeviation: [4, 4],
+ });
+ ctx.fillRect(25, 25, 50, 50);
+ </script>
+</span>
+
+<span>
+ <div>mostly-y</div>
+ <canvas id="canvas3" width="100" height="100" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas3");
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'teal';
+ ctx.filter = new CanvasFilter({
+ name: 'gaussianBlur',
+ stdDeviation: [1, 4],
+ });
+ ctx.fillRect(25, 25, 50, 50);
+ </script>
+</span>
+
+<span>
+ <div>y-only</div>
+ <canvas id="canvas4" width="100" height="100" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas4");
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'teal';
+ ctx.filter = new CanvasFilter({
+ name: 'gaussianBlur',
+ stdDeviation: [0, 4],
+ });
+ ctx.fillRect(25, 25, 50, 50);
+ </script>
+</span>
+
+</div>
diff --git a/testing/web-platform/tests/html/canvas/element/filters/2d.filter.canvasFilterObject.gaussianBlur.x-only.tentative-expected.html b/testing/web-platform/tests/html/canvas/element/filters/2d.filter.canvasFilterObject.gaussianBlur.x-only.tentative-expected.html
deleted file mode 100644
index e611113e42..0000000000
--- a/testing/web-platform/tests/html/canvas/element/filters/2d.filter.canvasFilterObject.gaussianBlur.x-only.tentative-expected.html
+++ /dev/null
@@ -1,15 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<title>Canvas test: 2d.filter.canvasFilterObject.gaussianBlur.x-only.tentative</title>
-<h1>2d.filter.canvasFilterObject.gaussianBlur.x-only.tentative</h1>
-<p class="desc">Test CanvasFilter() with gaussianBlur.</p>
-
-<svg xmlns="http://www.w3.org/2000/svg"
- width="100" height="100"
- color-interpolation-filters="sRGB">
- <filter id="blur" x="-50%" y="-50%" width="200%" height="200%">
- <feGaussianBlur stdDeviation="4 0" />
- </filter>
- <rect x="25" y="25" width="50" height="50"
- fill="teal" filter="url(#blur)" />
-</svg>
diff --git a/testing/web-platform/tests/html/canvas/element/filters/2d.filter.canvasFilterObject.gaussianBlur.x-only.tentative.html b/testing/web-platform/tests/html/canvas/element/filters/2d.filter.canvasFilterObject.gaussianBlur.x-only.tentative.html
deleted file mode 100644
index 4e8576fe74..0000000000
--- a/testing/web-platform/tests/html/canvas/element/filters/2d.filter.canvasFilterObject.gaussianBlur.x-only.tentative.html
+++ /dev/null
@@ -1,20 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<link rel="match" href="2d.filter.canvasFilterObject.gaussianBlur.x-only.tentative-expected.html">
-<title>Canvas test: 2d.filter.canvasFilterObject.gaussianBlur.x-only.tentative</title>
-<h1>2d.filter.canvasFilterObject.gaussianBlur.x-only.tentative</h1>
-<p class="desc">Test CanvasFilter() with gaussianBlur.</p>
-<canvas id="canvas" width="100" height="100">
- <p class="fallback">FAIL (fallback content)</p>
-</canvas>
-<script>
- const canvas = document.getElementById("canvas");
- const ctx = canvas.getContext('2d');
-
- ctx.fillStyle = 'teal';
- ctx.filter = new CanvasFilter({
- name: 'gaussianBlur',
- stdDeviation: [4, 0],
- });
- ctx.fillRect(25, 25, 50, 50);
-</script>
diff --git a/testing/web-platform/tests/html/canvas/element/filters/2d.filter.canvasFilterObject.gaussianBlur.y-only.tentative-expected.html b/testing/web-platform/tests/html/canvas/element/filters/2d.filter.canvasFilterObject.gaussianBlur.y-only.tentative-expected.html
deleted file mode 100644
index c6d915cb07..0000000000
--- a/testing/web-platform/tests/html/canvas/element/filters/2d.filter.canvasFilterObject.gaussianBlur.y-only.tentative-expected.html
+++ /dev/null
@@ -1,15 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<title>Canvas test: 2d.filter.canvasFilterObject.gaussianBlur.y-only.tentative</title>
-<h1>2d.filter.canvasFilterObject.gaussianBlur.y-only.tentative</h1>
-<p class="desc">Test CanvasFilter() with gaussianBlur.</p>
-
-<svg xmlns="http://www.w3.org/2000/svg"
- width="100" height="100"
- color-interpolation-filters="sRGB">
- <filter id="blur" x="-50%" y="-50%" width="200%" height="200%">
- <feGaussianBlur stdDeviation="0 4" />
- </filter>
- <rect x="25" y="25" width="50" height="50"
- fill="teal" filter="url(#blur)" />
-</svg>
diff --git a/testing/web-platform/tests/html/canvas/element/filters/2d.filter.canvasFilterObject.gaussianBlur.y-only.tentative.html b/testing/web-platform/tests/html/canvas/element/filters/2d.filter.canvasFilterObject.gaussianBlur.y-only.tentative.html
deleted file mode 100644
index ec0a2353cf..0000000000
--- a/testing/web-platform/tests/html/canvas/element/filters/2d.filter.canvasFilterObject.gaussianBlur.y-only.tentative.html
+++ /dev/null
@@ -1,20 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<link rel="match" href="2d.filter.canvasFilterObject.gaussianBlur.y-only.tentative-expected.html">
-<title>Canvas test: 2d.filter.canvasFilterObject.gaussianBlur.y-only.tentative</title>
-<h1>2d.filter.canvasFilterObject.gaussianBlur.y-only.tentative</h1>
-<p class="desc">Test CanvasFilter() with gaussianBlur.</p>
-<canvas id="canvas" width="100" height="100">
- <p class="fallback">FAIL (fallback content)</p>
-</canvas>
-<script>
- const canvas = document.getElementById("canvas");
- const ctx = canvas.getContext('2d');
-
- ctx.fillStyle = 'teal';
- ctx.filter = new CanvasFilter({
- name: 'gaussianBlur',
- stdDeviation: [0, 4],
- });
- ctx.fillRect(25, 25, 50, 50);
-</script>
diff --git a/testing/web-platform/tests/html/canvas/element/filters/2d.filter.layers.gaussianBlur-expected.html b/testing/web-platform/tests/html/canvas/element/filters/2d.filter.layers.gaussianBlur-expected.html
new file mode 100644
index 0000000000..f24e9d0dba
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/element/filters/2d.filter.layers.gaussianBlur-expected.html
@@ -0,0 +1,85 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<title>Canvas test: 2d.filter.layers.gaussianBlur</title>
+<h1 style="font-size: 20px;">2d.filter.layers.gaussianBlur</h1>
+<p class="desc">Test CanvasFilter() with gaussianBlur.</p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(5, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>x-only</div>
+ <div style="width: 100px; height: 100px; outline: 1px solid">
+ <svg xmlns="http://www.w3.org/2000/svg"
+ width="100" height="100"
+ color-interpolation-filters="sRGB">
+ <filter id="blur0" x="-50%" y="-50%" width="200%" height="200%">
+ <feGaussianBlur stdDeviation="4 0" />
+ </filter>
+ <rect x="25" y="25" width="50" height="50"
+ fill="teal" filter="url(#blur0)" />
+ </svg>
+ </div>
+</span>
+
+<span>
+ <div>mostly-x</div>
+ <div style="width: 100px; height: 100px; outline: 1px solid">
+ <svg xmlns="http://www.w3.org/2000/svg"
+ width="100" height="100"
+ color-interpolation-filters="sRGB">
+ <filter id="blur1" x="-50%" y="-50%" width="200%" height="200%">
+ <feGaussianBlur stdDeviation="4 1" />
+ </filter>
+ <rect x="25" y="25" width="50" height="50"
+ fill="teal" filter="url(#blur1)" />
+ </svg>
+ </div>
+</span>
+
+<span>
+ <div>isotropic</div>
+ <div style="width: 100px; height: 100px; outline: 1px solid">
+ <svg xmlns="http://www.w3.org/2000/svg"
+ width="100" height="100"
+ color-interpolation-filters="sRGB">
+ <filter id="blur2" x="-50%" y="-50%" width="200%" height="200%">
+ <feGaussianBlur stdDeviation="4 4" />
+ </filter>
+ <rect x="25" y="25" width="50" height="50"
+ fill="teal" filter="url(#blur2)" />
+ </svg>
+ </div>
+</span>
+
+<span>
+ <div>mostly-y</div>
+ <div style="width: 100px; height: 100px; outline: 1px solid">
+ <svg xmlns="http://www.w3.org/2000/svg"
+ width="100" height="100"
+ color-interpolation-filters="sRGB">
+ <filter id="blur3" x="-50%" y="-50%" width="200%" height="200%">
+ <feGaussianBlur stdDeviation="1 4" />
+ </filter>
+ <rect x="25" y="25" width="50" height="50"
+ fill="teal" filter="url(#blur3)" />
+ </svg>
+ </div>
+</span>
+
+<span>
+ <div>y-only</div>
+ <div style="width: 100px; height: 100px; outline: 1px solid">
+ <svg xmlns="http://www.w3.org/2000/svg"
+ width="100" height="100"
+ color-interpolation-filters="sRGB">
+ <filter id="blur4" x="-50%" y="-50%" width="200%" height="200%">
+ <feGaussianBlur stdDeviation="0 4" />
+ </filter>
+ <rect x="25" y="25" width="50" height="50"
+ fill="teal" filter="url(#blur4)" />
+ </svg>
+ </div>
+</span>
+
+</div>
diff --git a/testing/web-platform/tests/html/canvas/element/filters/2d.filter.layers.gaussianBlur.html b/testing/web-platform/tests/html/canvas/element/filters/2d.filter.layers.gaussianBlur.html
new file mode 100644
index 0000000000..19db679076
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/element/filters/2d.filter.layers.gaussianBlur.html
@@ -0,0 +1,106 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<link rel="match" href="2d.filter.layers.gaussianBlur-expected.html">
+<title>Canvas test: 2d.filter.layers.gaussianBlur</title>
+<h1 style="font-size: 20px;">2d.filter.layers.gaussianBlur</h1>
+<p class="desc">Test CanvasFilter() with gaussianBlur.</p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(5, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>x-only</div>
+ <canvas id="canvas0" width="100" height="100" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas0");
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'teal';
+ ctx.beginLayer({filter: {
+ name: 'gaussianBlur',
+ stdDeviation: [4, 0],
+ }});
+ ctx.fillRect(25, 25, 50, 50);
+ ctx.endLayer();
+ </script>
+</span>
+
+<span>
+ <div>mostly-x</div>
+ <canvas id="canvas1" width="100" height="100" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas1");
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'teal';
+ ctx.beginLayer({filter: {
+ name: 'gaussianBlur',
+ stdDeviation: [4, 1],
+ }});
+ ctx.fillRect(25, 25, 50, 50);
+ ctx.endLayer();
+ </script>
+</span>
+
+<span>
+ <div>isotropic</div>
+ <canvas id="canvas2" width="100" height="100" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas2");
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'teal';
+ ctx.beginLayer({filter: {
+ name: 'gaussianBlur',
+ stdDeviation: [4, 4],
+ }});
+ ctx.fillRect(25, 25, 50, 50);
+ ctx.endLayer();
+ </script>
+</span>
+
+<span>
+ <div>mostly-y</div>
+ <canvas id="canvas3" width="100" height="100" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas3");
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'teal';
+ ctx.beginLayer({filter: {
+ name: 'gaussianBlur',
+ stdDeviation: [1, 4],
+ }});
+ ctx.fillRect(25, 25, 50, 50);
+ ctx.endLayer();
+ </script>
+</span>
+
+<span>
+ <div>y-only</div>
+ <canvas id="canvas4" width="100" height="100" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas4");
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'teal';
+ ctx.beginLayer({filter: {
+ name: 'gaussianBlur',
+ stdDeviation: [0, 4],
+ }});
+ ctx.fillRect(25, 25, 50, 50);
+ ctx.endLayer();
+ </script>
+</span>
+
+</div>
diff --git a/testing/web-platform/tests/html/canvas/element/filters/2d.filter.layers.gaussianBlur.isotropic-expected.html b/testing/web-platform/tests/html/canvas/element/filters/2d.filter.layers.gaussianBlur.isotropic-expected.html
deleted file mode 100644
index 4f93754862..0000000000
--- a/testing/web-platform/tests/html/canvas/element/filters/2d.filter.layers.gaussianBlur.isotropic-expected.html
+++ /dev/null
@@ -1,15 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<title>Canvas test: 2d.filter.layers.gaussianBlur.isotropic</title>
-<h1>2d.filter.layers.gaussianBlur.isotropic</h1>
-<p class="desc">Test CanvasFilter() with gaussianBlur.</p>
-
-<svg xmlns="http://www.w3.org/2000/svg"
- width="100" height="100"
- color-interpolation-filters="sRGB">
- <filter id="blur" x="-50%" y="-50%" width="200%" height="200%">
- <feGaussianBlur stdDeviation="4 4" />
- </filter>
- <rect x="25" y="25" width="50" height="50"
- fill="teal" filter="url(#blur)" />
-</svg>
diff --git a/testing/web-platform/tests/html/canvas/element/filters/2d.filter.layers.gaussianBlur.isotropic.html b/testing/web-platform/tests/html/canvas/element/filters/2d.filter.layers.gaussianBlur.isotropic.html
deleted file mode 100644
index a2cc098896..0000000000
--- a/testing/web-platform/tests/html/canvas/element/filters/2d.filter.layers.gaussianBlur.isotropic.html
+++ /dev/null
@@ -1,21 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<link rel="match" href="2d.filter.layers.gaussianBlur.isotropic-expected.html">
-<title>Canvas test: 2d.filter.layers.gaussianBlur.isotropic</title>
-<h1>2d.filter.layers.gaussianBlur.isotropic</h1>
-<p class="desc">Test CanvasFilter() with gaussianBlur.</p>
-<canvas id="canvas" width="100" height="100">
- <p class="fallback">FAIL (fallback content)</p>
-</canvas>
-<script>
- const canvas = document.getElementById("canvas");
- const ctx = canvas.getContext('2d');
-
- ctx.fillStyle = 'teal';
- ctx.beginLayer({filter: {
- name: 'gaussianBlur',
- stdDeviation: [4, 4],
- }});
- ctx.fillRect(25, 25, 50, 50);
- ctx.endLayer();
-</script>
diff --git a/testing/web-platform/tests/html/canvas/element/filters/2d.filter.layers.gaussianBlur.mostly-x-expected.html b/testing/web-platform/tests/html/canvas/element/filters/2d.filter.layers.gaussianBlur.mostly-x-expected.html
deleted file mode 100644
index 255270c192..0000000000
--- a/testing/web-platform/tests/html/canvas/element/filters/2d.filter.layers.gaussianBlur.mostly-x-expected.html
+++ /dev/null
@@ -1,15 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<title>Canvas test: 2d.filter.layers.gaussianBlur.mostly-x</title>
-<h1>2d.filter.layers.gaussianBlur.mostly-x</h1>
-<p class="desc">Test CanvasFilter() with gaussianBlur.</p>
-
-<svg xmlns="http://www.w3.org/2000/svg"
- width="100" height="100"
- color-interpolation-filters="sRGB">
- <filter id="blur" x="-50%" y="-50%" width="200%" height="200%">
- <feGaussianBlur stdDeviation="4 1" />
- </filter>
- <rect x="25" y="25" width="50" height="50"
- fill="teal" filter="url(#blur)" />
-</svg>
diff --git a/testing/web-platform/tests/html/canvas/element/filters/2d.filter.layers.gaussianBlur.mostly-x.html b/testing/web-platform/tests/html/canvas/element/filters/2d.filter.layers.gaussianBlur.mostly-x.html
deleted file mode 100644
index 0090e0e71e..0000000000
--- a/testing/web-platform/tests/html/canvas/element/filters/2d.filter.layers.gaussianBlur.mostly-x.html
+++ /dev/null
@@ -1,21 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<link rel="match" href="2d.filter.layers.gaussianBlur.mostly-x-expected.html">
-<title>Canvas test: 2d.filter.layers.gaussianBlur.mostly-x</title>
-<h1>2d.filter.layers.gaussianBlur.mostly-x</h1>
-<p class="desc">Test CanvasFilter() with gaussianBlur.</p>
-<canvas id="canvas" width="100" height="100">
- <p class="fallback">FAIL (fallback content)</p>
-</canvas>
-<script>
- const canvas = document.getElementById("canvas");
- const ctx = canvas.getContext('2d');
-
- ctx.fillStyle = 'teal';
- ctx.beginLayer({filter: {
- name: 'gaussianBlur',
- stdDeviation: [4, 1],
- }});
- ctx.fillRect(25, 25, 50, 50);
- ctx.endLayer();
-</script>
diff --git a/testing/web-platform/tests/html/canvas/element/filters/2d.filter.layers.gaussianBlur.mostly-y-expected.html b/testing/web-platform/tests/html/canvas/element/filters/2d.filter.layers.gaussianBlur.mostly-y-expected.html
deleted file mode 100644
index 76a46b1533..0000000000
--- a/testing/web-platform/tests/html/canvas/element/filters/2d.filter.layers.gaussianBlur.mostly-y-expected.html
+++ /dev/null
@@ -1,15 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<title>Canvas test: 2d.filter.layers.gaussianBlur.mostly-y</title>
-<h1>2d.filter.layers.gaussianBlur.mostly-y</h1>
-<p class="desc">Test CanvasFilter() with gaussianBlur.</p>
-
-<svg xmlns="http://www.w3.org/2000/svg"
- width="100" height="100"
- color-interpolation-filters="sRGB">
- <filter id="blur" x="-50%" y="-50%" width="200%" height="200%">
- <feGaussianBlur stdDeviation="1 4" />
- </filter>
- <rect x="25" y="25" width="50" height="50"
- fill="teal" filter="url(#blur)" />
-</svg>
diff --git a/testing/web-platform/tests/html/canvas/element/filters/2d.filter.layers.gaussianBlur.mostly-y.html b/testing/web-platform/tests/html/canvas/element/filters/2d.filter.layers.gaussianBlur.mostly-y.html
deleted file mode 100644
index 5c481cbe25..0000000000
--- a/testing/web-platform/tests/html/canvas/element/filters/2d.filter.layers.gaussianBlur.mostly-y.html
+++ /dev/null
@@ -1,21 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<link rel="match" href="2d.filter.layers.gaussianBlur.mostly-y-expected.html">
-<title>Canvas test: 2d.filter.layers.gaussianBlur.mostly-y</title>
-<h1>2d.filter.layers.gaussianBlur.mostly-y</h1>
-<p class="desc">Test CanvasFilter() with gaussianBlur.</p>
-<canvas id="canvas" width="100" height="100">
- <p class="fallback">FAIL (fallback content)</p>
-</canvas>
-<script>
- const canvas = document.getElementById("canvas");
- const ctx = canvas.getContext('2d');
-
- ctx.fillStyle = 'teal';
- ctx.beginLayer({filter: {
- name: 'gaussianBlur',
- stdDeviation: [1, 4],
- }});
- ctx.fillRect(25, 25, 50, 50);
- ctx.endLayer();
-</script>
diff --git a/testing/web-platform/tests/html/canvas/element/filters/2d.filter.layers.gaussianBlur.x-only-expected.html b/testing/web-platform/tests/html/canvas/element/filters/2d.filter.layers.gaussianBlur.x-only-expected.html
deleted file mode 100644
index 26741f9847..0000000000
--- a/testing/web-platform/tests/html/canvas/element/filters/2d.filter.layers.gaussianBlur.x-only-expected.html
+++ /dev/null
@@ -1,15 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<title>Canvas test: 2d.filter.layers.gaussianBlur.x-only</title>
-<h1>2d.filter.layers.gaussianBlur.x-only</h1>
-<p class="desc">Test CanvasFilter() with gaussianBlur.</p>
-
-<svg xmlns="http://www.w3.org/2000/svg"
- width="100" height="100"
- color-interpolation-filters="sRGB">
- <filter id="blur" x="-50%" y="-50%" width="200%" height="200%">
- <feGaussianBlur stdDeviation="4 0" />
- </filter>
- <rect x="25" y="25" width="50" height="50"
- fill="teal" filter="url(#blur)" />
-</svg>
diff --git a/testing/web-platform/tests/html/canvas/element/filters/2d.filter.layers.gaussianBlur.x-only.html b/testing/web-platform/tests/html/canvas/element/filters/2d.filter.layers.gaussianBlur.x-only.html
deleted file mode 100644
index f7940eb921..0000000000
--- a/testing/web-platform/tests/html/canvas/element/filters/2d.filter.layers.gaussianBlur.x-only.html
+++ /dev/null
@@ -1,21 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<link rel="match" href="2d.filter.layers.gaussianBlur.x-only-expected.html">
-<title>Canvas test: 2d.filter.layers.gaussianBlur.x-only</title>
-<h1>2d.filter.layers.gaussianBlur.x-only</h1>
-<p class="desc">Test CanvasFilter() with gaussianBlur.</p>
-<canvas id="canvas" width="100" height="100">
- <p class="fallback">FAIL (fallback content)</p>
-</canvas>
-<script>
- const canvas = document.getElementById("canvas");
- const ctx = canvas.getContext('2d');
-
- ctx.fillStyle = 'teal';
- ctx.beginLayer({filter: {
- name: 'gaussianBlur',
- stdDeviation: [4, 0],
- }});
- ctx.fillRect(25, 25, 50, 50);
- ctx.endLayer();
-</script>
diff --git a/testing/web-platform/tests/html/canvas/element/filters/2d.filter.layers.gaussianBlur.y-only-expected.html b/testing/web-platform/tests/html/canvas/element/filters/2d.filter.layers.gaussianBlur.y-only-expected.html
deleted file mode 100644
index d00eec6b57..0000000000
--- a/testing/web-platform/tests/html/canvas/element/filters/2d.filter.layers.gaussianBlur.y-only-expected.html
+++ /dev/null
@@ -1,15 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<title>Canvas test: 2d.filter.layers.gaussianBlur.y-only</title>
-<h1>2d.filter.layers.gaussianBlur.y-only</h1>
-<p class="desc">Test CanvasFilter() with gaussianBlur.</p>
-
-<svg xmlns="http://www.w3.org/2000/svg"
- width="100" height="100"
- color-interpolation-filters="sRGB">
- <filter id="blur" x="-50%" y="-50%" width="200%" height="200%">
- <feGaussianBlur stdDeviation="0 4" />
- </filter>
- <rect x="25" y="25" width="50" height="50"
- fill="teal" filter="url(#blur)" />
-</svg>
diff --git a/testing/web-platform/tests/html/canvas/element/filters/2d.filter.layers.gaussianBlur.y-only.html b/testing/web-platform/tests/html/canvas/element/filters/2d.filter.layers.gaussianBlur.y-only.html
deleted file mode 100644
index 59421a1ff3..0000000000
--- a/testing/web-platform/tests/html/canvas/element/filters/2d.filter.layers.gaussianBlur.y-only.html
+++ /dev/null
@@ -1,21 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<link rel="match" href="2d.filter.layers.gaussianBlur.y-only-expected.html">
-<title>Canvas test: 2d.filter.layers.gaussianBlur.y-only</title>
-<h1>2d.filter.layers.gaussianBlur.y-only</h1>
-<p class="desc">Test CanvasFilter() with gaussianBlur.</p>
-<canvas id="canvas" width="100" height="100">
- <p class="fallback">FAIL (fallback content)</p>
-</canvas>
-<script>
- const canvas = document.getElementById("canvas");
- const ctx = canvas.getContext('2d');
-
- ctx.fillStyle = 'teal';
- ctx.beginLayer({filter: {
- name: 'gaussianBlur',
- stdDeviation: [0, 4],
- }});
- ctx.fillRect(25, 25, 50, 50);
- ctx.endLayer();
-</script>
diff --git a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.beginLayer-options.html b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.beginLayer-options.html
index 658d7e0991..573d300055 100644
--- a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.beginLayer-options.html
+++ b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.beginLayer-options.html
@@ -16,8 +16,9 @@
<ul id="d"></ul>
<script>
-var t = async_test("Checks beginLayer works for different option parameter values");
-_addTest(function(canvas, ctx) {
+test(t => {
+ var canvas = document.getElementById('c');
+ var ctx = canvas.getContext('2d');
ctx.beginLayer(); ctx.endLayer();
ctx.beginLayer(null); ctx.endLayer();
@@ -45,6 +46,6 @@ _addTest(function(canvas, ctx) {
ctx.beginLayer({filter: true}); ctx.endLayer();
ctx.beginLayer({filter: false}); ctx.endLayer();
-});
+}, "Checks beginLayer works for different option parameter values");
</script>
diff --git a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.ctm.getTransform.html b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.ctm.getTransform.html
index 7a69c59527..d669b3c522 100644
--- a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.ctm.getTransform.html
+++ b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.ctm.getTransform.html
@@ -16,8 +16,9 @@
<ul id="d"></ul>
<script>
-var t = async_test("Tests getTransform inside layers.");
-_addTest(function(canvas, ctx) {
+test(t => {
+ var canvas = document.getElementById('c');
+ var ctx = canvas.getContext('2d');
ctx.translate(10, 20);
ctx.beginLayer();
@@ -26,6 +27,6 @@ _addTest(function(canvas, ctx) {
assert_array_equals([m.a, m.b, m.c, m.d, m.e, m.f], [2, 0, 0, 3, 10, 20]);
ctx.endLayer();
-});
+}, "Tests getTransform inside layers.");
</script>
diff --git a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.exceptions-are-no-op.html b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.exceptions-are-no-op.html
index 7ab2080fca..facffd74e9 100644
--- a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.exceptions-are-no-op.html
+++ b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.exceptions-are-no-op.html
@@ -16,8 +16,9 @@
<ul id="d"></ul>
<script>
-var t = async_test("Checks that the context state is left unchanged if beginLayer throws.");
-_addTest(function(canvas, ctx) {
+test(t => {
+ var canvas = document.getElementById('c');
+ var ctx = canvas.getContext('2d');
// Get `beginLayer` to throw while parsing the filter.
assert_throws_js(TypeError,
@@ -26,6 +27,6 @@ _addTest(function(canvas, ctx) {
// `beginLayer` shouldn't have opened the layer, so `endLayer` should throw.
assert_throws_dom("InvalidStateError", () => ctx.endLayer());
-});
+}, "Checks that the context state is left unchanged if beginLayer throws.");
</script>
diff --git a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.alpha-expected.html b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.alpha-expected.html
deleted file mode 100644
index 0666e3098a..0000000000
--- a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.alpha-expected.html
+++ /dev/null
@@ -1,31 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<title>Canvas test: 2d.layer.global-states.alpha</title>
-<h1>2d.layer.global-states.alpha</h1>
-<p class="desc">Checks that layers correctly use global render states.</p>
-<canvas id="canvas" width="200" height="200">
- <p class="fallback">FAIL (fallback content)</p>
-</canvas>
-<script>
- const canvas = document.getElementById("canvas");
- const ctx = canvas.getContext('2d');
-
- ctx.fillStyle = 'rgba(0, 0, 255, 1)';
-
- var circle = new Path2D();
- circle.arc(90, 90, 45, 0, 2 * Math.PI);
- ctx.fill(circle);
-
- ctx.globalAlpha = 0.6;
-
- canvas2 = document.createElement("canvas");
- ctx2 = canvas2.getContext("2d");
-
- ctx2.globalCompositeOperation = 'screen';
- ctx2.fillStyle = 'rgba(225, 0, 0, 1)';
- ctx2.fillRect(50, 50, 75, 50);
- ctx2.fillStyle = 'rgba(0, 255, 0, 1)';
- ctx2.fillRect(70, 70, 75, 50);
-
- ctx.drawImage(canvas2, 0, 0);
-</script>
diff --git a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.alpha.blending-expected.html b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.alpha.blending-expected.html
deleted file mode 100644
index 8a45027588..0000000000
--- a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.alpha.blending-expected.html
+++ /dev/null
@@ -1,32 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<title>Canvas test: 2d.layer.global-states.alpha.blending</title>
-<h1>2d.layer.global-states.alpha.blending</h1>
-<p class="desc">Checks that layers correctly use global render states.</p>
-<canvas id="canvas" width="200" height="200">
- <p class="fallback">FAIL (fallback content)</p>
-</canvas>
-<script>
- const canvas = document.getElementById("canvas");
- const ctx = canvas.getContext('2d');
-
- ctx.fillStyle = 'rgba(0, 0, 255, 1)';
-
- var circle = new Path2D();
- circle.arc(90, 90, 45, 0, 2 * Math.PI);
- ctx.fill(circle);
-
- ctx.globalAlpha = 0.6;
- ctx.globalCompositeOperation = 'multiply';
-
- canvas2 = document.createElement("canvas");
- ctx2 = canvas2.getContext("2d");
-
- ctx2.globalCompositeOperation = 'screen';
- ctx2.fillStyle = 'rgba(225, 0, 0, 1)';
- ctx2.fillRect(50, 50, 75, 50);
- ctx2.fillStyle = 'rgba(0, 255, 0, 1)';
- ctx2.fillRect(70, 70, 75, 50);
-
- ctx.drawImage(canvas2, 0, 0);
-</script>
diff --git a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.alpha.blending.html b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.alpha.blending.html
deleted file mode 100644
index 8e15a2b936..0000000000
--- a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.alpha.blending.html
+++ /dev/null
@@ -1,35 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<link rel="match" href="2d.layer.global-states.alpha.blending-expected.html">
-<title>Canvas test: 2d.layer.global-states.alpha.blending</title>
-<h1>2d.layer.global-states.alpha.blending</h1>
-<p class="desc">Checks that layers correctly use global render states.</p>
-<canvas id="canvas" width="200" height="200">
- <p class="fallback">FAIL (fallback content)</p>
-</canvas>
-<script>
- const canvas = document.getElementById("canvas");
- const ctx = canvas.getContext('2d');
-
- ctx.fillStyle = 'rgba(0, 0, 255, 1)';
-
- var circle = new Path2D();
- circle.arc(90, 90, 45, 0, 2 * Math.PI);
- ctx.fill(circle);
-
- ctx.globalAlpha = 0.6;
- ctx.globalCompositeOperation = 'multiply';
-
- ctx.beginLayer();
-
- // Enable compositing in the layer to validate that draw calls in the layer
- // 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(0, 255, 0, 1)';
- ctx.fillRect(70, 70, 75, 50);
-
- ctx.endLayer();
-</script>
diff --git a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.alpha.blending.shadow-expected.html b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.alpha.blending.shadow-expected.html
deleted file mode 100644
index f7b633b35f..0000000000
--- a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.alpha.blending.shadow-expected.html
+++ /dev/null
@@ -1,36 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<title>Canvas test: 2d.layer.global-states.alpha.blending.shadow</title>
-<h1>2d.layer.global-states.alpha.blending.shadow</h1>
-<p class="desc">Checks that layers correctly use global render states.</p>
-<canvas id="canvas" width="200" height="200">
- <p class="fallback">FAIL (fallback content)</p>
-</canvas>
-<script>
- const canvas = document.getElementById("canvas");
- const ctx = canvas.getContext('2d');
-
- ctx.fillStyle = 'rgba(0, 0, 255, 1)';
-
- var circle = new Path2D();
- circle.arc(90, 90, 45, 0, 2 * Math.PI);
- ctx.fill(circle);
-
- ctx.globalAlpha = 0.6;
- ctx.globalCompositeOperation = 'multiply';
- ctx.shadowOffsetX = -10;
- ctx.shadowOffsetY = 10;
- ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
- ctx.shadowBlur = 3;
-
- canvas2 = document.createElement("canvas");
- ctx2 = canvas2.getContext("2d");
-
- ctx2.globalCompositeOperation = 'screen';
- ctx2.fillStyle = 'rgba(225, 0, 0, 1)';
- ctx2.fillRect(50, 50, 75, 50);
- ctx2.fillStyle = 'rgba(0, 255, 0, 1)';
- ctx2.fillRect(70, 70, 75, 50);
-
- ctx.drawImage(canvas2, 0, 0);
-</script>
diff --git a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.alpha.blending.shadow.html b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.alpha.blending.shadow.html
deleted file mode 100644
index c8c6d433bc..0000000000
--- a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.alpha.blending.shadow.html
+++ /dev/null
@@ -1,39 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<link rel="match" href="2d.layer.global-states.alpha.blending.shadow-expected.html">
-<title>Canvas test: 2d.layer.global-states.alpha.blending.shadow</title>
-<h1>2d.layer.global-states.alpha.blending.shadow</h1>
-<p class="desc">Checks that layers correctly use global render states.</p>
-<canvas id="canvas" width="200" height="200">
- <p class="fallback">FAIL (fallback content)</p>
-</canvas>
-<script>
- const canvas = document.getElementById("canvas");
- const ctx = canvas.getContext('2d');
-
- ctx.fillStyle = 'rgba(0, 0, 255, 1)';
-
- var circle = new Path2D();
- circle.arc(90, 90, 45, 0, 2 * Math.PI);
- ctx.fill(circle);
-
- ctx.globalAlpha = 0.6;
- ctx.globalCompositeOperation = 'multiply';
- ctx.shadowOffsetX = -10;
- ctx.shadowOffsetY = 10;
- ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
- ctx.shadowBlur = 3;
-
- ctx.beginLayer();
-
- // Enable compositing in the layer to validate that draw calls in the layer
- // 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(0, 255, 0, 1)';
- ctx.fillRect(70, 70, 75, 50);
-
- ctx.endLayer();
-</script>
diff --git a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.alpha.composite-expected.html b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.alpha.composite-expected.html
deleted file mode 100644
index 951049e638..0000000000
--- a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.alpha.composite-expected.html
+++ /dev/null
@@ -1,32 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<title>Canvas test: 2d.layer.global-states.alpha.composite</title>
-<h1>2d.layer.global-states.alpha.composite</h1>
-<p class="desc">Checks that layers correctly use global render states.</p>
-<canvas id="canvas" width="200" height="200">
- <p class="fallback">FAIL (fallback content)</p>
-</canvas>
-<script>
- const canvas = document.getElementById("canvas");
- const ctx = canvas.getContext('2d');
-
- ctx.fillStyle = 'rgba(0, 0, 255, 1)';
-
- var circle = new Path2D();
- circle.arc(90, 90, 45, 0, 2 * Math.PI);
- ctx.fill(circle);
-
- ctx.globalAlpha = 0.6;
- ctx.globalCompositeOperation = 'source-in';
-
- canvas2 = document.createElement("canvas");
- ctx2 = canvas2.getContext("2d");
-
- ctx2.globalCompositeOperation = 'screen';
- ctx2.fillStyle = 'rgba(225, 0, 0, 1)';
- ctx2.fillRect(50, 50, 75, 50);
- ctx2.fillStyle = 'rgba(0, 255, 0, 1)';
- ctx2.fillRect(70, 70, 75, 50);
-
- ctx.drawImage(canvas2, 0, 0);
-</script>
diff --git a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.alpha.composite.html b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.alpha.composite.html
deleted file mode 100644
index 1ac6a2cbfe..0000000000
--- a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.alpha.composite.html
+++ /dev/null
@@ -1,35 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<link rel="match" href="2d.layer.global-states.alpha.composite-expected.html">
-<title>Canvas test: 2d.layer.global-states.alpha.composite</title>
-<h1>2d.layer.global-states.alpha.composite</h1>
-<p class="desc">Checks that layers correctly use global render states.</p>
-<canvas id="canvas" width="200" height="200">
- <p class="fallback">FAIL (fallback content)</p>
-</canvas>
-<script>
- const canvas = document.getElementById("canvas");
- const ctx = canvas.getContext('2d');
-
- ctx.fillStyle = 'rgba(0, 0, 255, 1)';
-
- var circle = new Path2D();
- circle.arc(90, 90, 45, 0, 2 * Math.PI);
- ctx.fill(circle);
-
- ctx.globalAlpha = 0.6;
- ctx.globalCompositeOperation = 'source-in';
-
- ctx.beginLayer();
-
- // Enable compositing in the layer to validate that draw calls in the layer
- // 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(0, 255, 0, 1)';
- ctx.fillRect(70, 70, 75, 50);
-
- ctx.endLayer();
-</script>
diff --git a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.alpha.composite.shadow-expected.html b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.alpha.composite.shadow-expected.html
deleted file mode 100644
index 0ae93871f5..0000000000
--- a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.alpha.composite.shadow-expected.html
+++ /dev/null
@@ -1,36 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<title>Canvas test: 2d.layer.global-states.alpha.composite.shadow</title>
-<h1>2d.layer.global-states.alpha.composite.shadow</h1>
-<p class="desc">Checks that layers correctly use global render states.</p>
-<canvas id="canvas" width="200" height="200">
- <p class="fallback">FAIL (fallback content)</p>
-</canvas>
-<script>
- const canvas = document.getElementById("canvas");
- const ctx = canvas.getContext('2d');
-
- ctx.fillStyle = 'rgba(0, 0, 255, 1)';
-
- var circle = new Path2D();
- circle.arc(90, 90, 45, 0, 2 * Math.PI);
- ctx.fill(circle);
-
- 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;
-
- canvas2 = document.createElement("canvas");
- ctx2 = canvas2.getContext("2d");
-
- ctx2.globalCompositeOperation = 'screen';
- ctx2.fillStyle = 'rgba(225, 0, 0, 1)';
- ctx2.fillRect(50, 50, 75, 50);
- ctx2.fillStyle = 'rgba(0, 255, 0, 1)';
- ctx2.fillRect(70, 70, 75, 50);
-
- ctx.drawImage(canvas2, 0, 0);
-</script>
diff --git a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.alpha.composite.shadow.html b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.alpha.composite.shadow.html
deleted file mode 100644
index 92b8a0d7a7..0000000000
--- a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.alpha.composite.shadow.html
+++ /dev/null
@@ -1,39 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<link rel="match" href="2d.layer.global-states.alpha.composite.shadow-expected.html">
-<title>Canvas test: 2d.layer.global-states.alpha.composite.shadow</title>
-<h1>2d.layer.global-states.alpha.composite.shadow</h1>
-<p class="desc">Checks that layers correctly use global render states.</p>
-<canvas id="canvas" width="200" height="200">
- <p class="fallback">FAIL (fallback content)</p>
-</canvas>
-<script>
- const canvas = document.getElementById("canvas");
- const ctx = canvas.getContext('2d');
-
- ctx.fillStyle = 'rgba(0, 0, 255, 1)';
-
- var circle = new Path2D();
- circle.arc(90, 90, 45, 0, 2 * Math.PI);
- ctx.fill(circle);
-
- 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;
-
- ctx.beginLayer();
-
- // Enable compositing in the layer to validate that draw calls in the layer
- // 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(0, 255, 0, 1)';
- ctx.fillRect(70, 70, 75, 50);
-
- ctx.endLayer();
-</script>
diff --git a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.alpha.html b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.alpha.html
deleted file mode 100644
index 829796acbf..0000000000
--- a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.alpha.html
+++ /dev/null
@@ -1,34 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<link rel="match" href="2d.layer.global-states.alpha-expected.html">
-<title>Canvas test: 2d.layer.global-states.alpha</title>
-<h1>2d.layer.global-states.alpha</h1>
-<p class="desc">Checks that layers correctly use global render states.</p>
-<canvas id="canvas" width="200" height="200">
- <p class="fallback">FAIL (fallback content)</p>
-</canvas>
-<script>
- const canvas = document.getElementById("canvas");
- const ctx = canvas.getContext('2d');
-
- ctx.fillStyle = 'rgba(0, 0, 255, 1)';
-
- var circle = new Path2D();
- circle.arc(90, 90, 45, 0, 2 * Math.PI);
- ctx.fill(circle);
-
- ctx.globalAlpha = 0.6;
-
- ctx.beginLayer();
-
- // Enable compositing in the layer to validate that draw calls in the layer
- // 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(0, 255, 0, 1)';
- ctx.fillRect(70, 70, 75, 50);
-
- ctx.endLayer();
-</script>
diff --git a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.alpha.shadow-expected.html b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.alpha.shadow-expected.html
deleted file mode 100644
index 6f764c5001..0000000000
--- a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.alpha.shadow-expected.html
+++ /dev/null
@@ -1,35 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<title>Canvas test: 2d.layer.global-states.alpha.shadow</title>
-<h1>2d.layer.global-states.alpha.shadow</h1>
-<p class="desc">Checks that layers correctly use global render states.</p>
-<canvas id="canvas" width="200" height="200">
- <p class="fallback">FAIL (fallback content)</p>
-</canvas>
-<script>
- const canvas = document.getElementById("canvas");
- const ctx = canvas.getContext('2d');
-
- ctx.fillStyle = 'rgba(0, 0, 255, 1)';
-
- var circle = new Path2D();
- circle.arc(90, 90, 45, 0, 2 * Math.PI);
- ctx.fill(circle);
-
- ctx.globalAlpha = 0.5;
- ctx.shadowOffsetX = -10;
- ctx.shadowOffsetY = 10;
- ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
- ctx.shadowBlur = 3;
-
- canvas2 = document.createElement("canvas");
- ctx2 = canvas2.getContext("2d");
-
- ctx2.globalCompositeOperation = 'screen';
- ctx2.fillStyle = 'rgba(225, 0, 0, 1)';
- ctx2.fillRect(50, 50, 75, 50);
- ctx2.fillStyle = 'rgba(0, 255, 0, 1)';
- ctx2.fillRect(70, 70, 75, 50);
-
- ctx.drawImage(canvas2, 0, 0);
-</script>
diff --git a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.alpha.shadow.html b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.alpha.shadow.html
deleted file mode 100644
index a325302b3b..0000000000
--- a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.alpha.shadow.html
+++ /dev/null
@@ -1,38 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<link rel="match" href="2d.layer.global-states.alpha.shadow-expected.html">
-<title>Canvas test: 2d.layer.global-states.alpha.shadow</title>
-<h1>2d.layer.global-states.alpha.shadow</h1>
-<p class="desc">Checks that layers correctly use global render states.</p>
-<canvas id="canvas" width="200" height="200">
- <p class="fallback">FAIL (fallback content)</p>
-</canvas>
-<script>
- const canvas = document.getElementById("canvas");
- const ctx = canvas.getContext('2d');
-
- ctx.fillStyle = 'rgba(0, 0, 255, 1)';
-
- var circle = new Path2D();
- circle.arc(90, 90, 45, 0, 2 * Math.PI);
- ctx.fill(circle);
-
- ctx.globalAlpha = 0.5;
- ctx.shadowOffsetX = -10;
- ctx.shadowOffsetY = 10;
- ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
- ctx.shadowBlur = 3;
-
- ctx.beginLayer();
-
- // Enable compositing in the layer to validate that draw calls in the layer
- // 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(0, 255, 0, 1)';
- ctx.fillRect(70, 70, 75, 50);
-
- ctx.endLayer();
-</script>
diff --git a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.blending-expected.html b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.blending-expected.html
deleted file mode 100644
index 33fdf46a28..0000000000
--- a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.blending-expected.html
+++ /dev/null
@@ -1,31 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<title>Canvas test: 2d.layer.global-states.blending</title>
-<h1>2d.layer.global-states.blending</h1>
-<p class="desc">Checks that layers correctly use global render states.</p>
-<canvas id="canvas" width="200" height="200">
- <p class="fallback">FAIL (fallback content)</p>
-</canvas>
-<script>
- const canvas = document.getElementById("canvas");
- const ctx = canvas.getContext('2d');
-
- ctx.fillStyle = 'rgba(0, 0, 255, 1)';
-
- var circle = new Path2D();
- circle.arc(90, 90, 45, 0, 2 * Math.PI);
- ctx.fill(circle);
-
- ctx.globalCompositeOperation = 'multiply';
-
- canvas2 = document.createElement("canvas");
- ctx2 = canvas2.getContext("2d");
-
- ctx2.globalCompositeOperation = 'screen';
- ctx2.fillStyle = 'rgba(225, 0, 0, 1)';
- ctx2.fillRect(50, 50, 75, 50);
- ctx2.fillStyle = 'rgba(0, 255, 0, 1)';
- ctx2.fillRect(70, 70, 75, 50);
-
- ctx.drawImage(canvas2, 0, 0);
-</script>
diff --git a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.blending.html b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.blending.html
deleted file mode 100644
index 7d4d9ae4b5..0000000000
--- a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.blending.html
+++ /dev/null
@@ -1,34 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<link rel="match" href="2d.layer.global-states.blending-expected.html">
-<title>Canvas test: 2d.layer.global-states.blending</title>
-<h1>2d.layer.global-states.blending</h1>
-<p class="desc">Checks that layers correctly use global render states.</p>
-<canvas id="canvas" width="200" height="200">
- <p class="fallback">FAIL (fallback content)</p>
-</canvas>
-<script>
- const canvas = document.getElementById("canvas");
- const ctx = canvas.getContext('2d');
-
- ctx.fillStyle = 'rgba(0, 0, 255, 1)';
-
- var circle = new Path2D();
- circle.arc(90, 90, 45, 0, 2 * Math.PI);
- ctx.fill(circle);
-
- ctx.globalCompositeOperation = 'multiply';
-
- ctx.beginLayer();
-
- // Enable compositing in the layer to validate that draw calls in the layer
- // 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(0, 255, 0, 1)';
- ctx.fillRect(70, 70, 75, 50);
-
- ctx.endLayer();
-</script>
diff --git a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.blending.no-shadow.no-transform-expected.html b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.blending.no-shadow.no-transform-expected.html
new file mode 100644
index 0000000000..c56f13f2fd
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.blending.no-shadow.no-transform-expected.html
@@ -0,0 +1,72 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<title>Canvas test: 2d.layer.global-states.blending.no-shadow.no-transform</title>
+<h1 style="font-size: 20px;">2d.layer.global-states.blending.no-shadow.no-transform</h1>
+<p class="desc">Checks that layers correctly use global render states.</p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(2, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>no-globalAlpha</div>
+ <canvas id="canvas0" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas0");
+ const ctx = canvas.getContext('2d');
+
+ // No transform.
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ // No globalAlpha.
+ ctx.globalCompositeOperation = 'multiply';
+ // No shadow.
+
+ const canvas2 = document.createElement("canvas");
+ const ctx2 = canvas2.getContext("2d");
+
+ ctx2.globalCompositeOperation = 'screen';
+ ctx2.fillStyle = 'rgba(255, 0, 0, 1)';
+ ctx2.fillRect(10, 25, 40, 50);
+ ctx2.fillStyle = 'rgba(0, 255, 0, 1)';
+ ctx2.fillRect(30, 5, 50, 40);
+
+ ctx.drawImage(canvas2, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>globalAlpha</div>
+ <canvas id="canvas1" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas1");
+ const ctx = canvas.getContext('2d');
+
+ // No transform.
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ ctx.globalAlpha = 0.75;
+ ctx.globalCompositeOperation = 'multiply';
+ // No shadow.
+
+ const canvas2 = document.createElement("canvas");
+ const ctx2 = canvas2.getContext("2d");
+
+ ctx2.globalCompositeOperation = 'screen';
+ ctx2.fillStyle = 'rgba(255, 0, 0, 1)';
+ ctx2.fillRect(10, 25, 40, 50);
+ ctx2.fillStyle = 'rgba(0, 255, 0, 1)';
+ ctx2.fillRect(30, 5, 50, 40);
+
+ ctx.drawImage(canvas2, 0, 0);
+ </script>
+</span>
+
+</div>
diff --git a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.blending.no-shadow.no-transform.html b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.blending.no-shadow.no-transform.html
new file mode 100644
index 0000000000..91decadfe2
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.blending.no-shadow.no-transform.html
@@ -0,0 +1,77 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<link rel="match" href="2d.layer.global-states.blending.no-shadow.no-transform-expected.html">
+<title>Canvas test: 2d.layer.global-states.blending.no-shadow.no-transform</title>
+<h1 style="font-size: 20px;">2d.layer.global-states.blending.no-shadow.no-transform</h1>
+<p class="desc">Checks that layers correctly use global render states.</p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(2, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>no-globalAlpha</div>
+ <canvas id="canvas0" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas0");
+ const ctx = canvas.getContext('2d');
+
+ // No transform.
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ // No globalAlpha.
+ ctx.globalCompositeOperation = 'multiply';
+ // No shadow.
+
+ ctx.beginLayer();
+
+ // Enable compositing in the layer to validate that draw calls in the layer
+ // won't individually composite with the background.
+ ctx.globalCompositeOperation = 'screen';
+
+ 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();
+ </script>
+</span>
+
+<span>
+ <div>globalAlpha</div>
+ <canvas id="canvas1" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas1");
+ const ctx = canvas.getContext('2d');
+
+ // No transform.
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ ctx.globalAlpha = 0.75;
+ ctx.globalCompositeOperation = 'multiply';
+ // No shadow.
+
+ ctx.beginLayer();
+
+ // Enable compositing in the layer to validate that draw calls in the layer
+ // won't individually composite with the background.
+ ctx.globalCompositeOperation = 'screen';
+
+ 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();
+ </script>
+</span>
+
+</div>
diff --git a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.blending.no-shadow.rotation-expected.html b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.blending.no-shadow.rotation-expected.html
new file mode 100644
index 0000000000..e5f8ba0db4
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.blending.no-shadow.rotation-expected.html
@@ -0,0 +1,76 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<title>Canvas test: 2d.layer.global-states.blending.no-shadow.rotation</title>
+<h1 style="font-size: 20px;">2d.layer.global-states.blending.no-shadow.rotation</h1>
+<p class="desc">Checks that layers correctly use global render states.</p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(2, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>no-globalAlpha</div>
+ <canvas id="canvas0" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas0");
+ const ctx = canvas.getContext('2d');
+
+ ctx.translate(50, 40);
+ ctx.rotate(Math.PI);
+ ctx.translate(-45, -45);
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ // No globalAlpha.
+ ctx.globalCompositeOperation = 'multiply';
+ // No shadow.
+
+ const canvas2 = document.createElement("canvas");
+ const ctx2 = canvas2.getContext("2d");
+
+ ctx2.globalCompositeOperation = 'screen';
+ ctx2.fillStyle = 'rgba(255, 0, 0, 1)';
+ ctx2.fillRect(10, 25, 40, 50);
+ ctx2.fillStyle = 'rgba(0, 255, 0, 1)';
+ ctx2.fillRect(30, 5, 50, 40);
+
+ ctx.drawImage(canvas2, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>globalAlpha</div>
+ <canvas id="canvas1" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas1");
+ const ctx = canvas.getContext('2d');
+
+ ctx.translate(50, 40);
+ ctx.rotate(Math.PI);
+ ctx.translate(-45, -45);
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ ctx.globalAlpha = 0.75;
+ ctx.globalCompositeOperation = 'multiply';
+ // No shadow.
+
+ const canvas2 = document.createElement("canvas");
+ const ctx2 = canvas2.getContext("2d");
+
+ ctx2.globalCompositeOperation = 'screen';
+ ctx2.fillStyle = 'rgba(255, 0, 0, 1)';
+ ctx2.fillRect(10, 25, 40, 50);
+ ctx2.fillStyle = 'rgba(0, 255, 0, 1)';
+ ctx2.fillRect(30, 5, 50, 40);
+
+ ctx.drawImage(canvas2, 0, 0);
+ </script>
+</span>
+
+</div>
diff --git a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.blending.no-shadow.rotation.html b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.blending.no-shadow.rotation.html
new file mode 100644
index 0000000000..d6b28315f2
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.blending.no-shadow.rotation.html
@@ -0,0 +1,81 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<link rel="match" href="2d.layer.global-states.blending.no-shadow.rotation-expected.html">
+<title>Canvas test: 2d.layer.global-states.blending.no-shadow.rotation</title>
+<h1 style="font-size: 20px;">2d.layer.global-states.blending.no-shadow.rotation</h1>
+<p class="desc">Checks that layers correctly use global render states.</p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(2, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>no-globalAlpha</div>
+ <canvas id="canvas0" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas0");
+ const ctx = canvas.getContext('2d');
+
+ ctx.translate(50, 40);
+ ctx.rotate(Math.PI);
+ ctx.translate(-45, -45);
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ // No globalAlpha.
+ ctx.globalCompositeOperation = 'multiply';
+ // No shadow.
+
+ ctx.beginLayer();
+
+ // Enable compositing in the layer to validate that draw calls in the layer
+ // won't individually composite with the background.
+ ctx.globalCompositeOperation = 'screen';
+
+ 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();
+ </script>
+</span>
+
+<span>
+ <div>globalAlpha</div>
+ <canvas id="canvas1" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas1");
+ const ctx = canvas.getContext('2d');
+
+ ctx.translate(50, 40);
+ ctx.rotate(Math.PI);
+ ctx.translate(-45, -45);
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ ctx.globalAlpha = 0.75;
+ ctx.globalCompositeOperation = 'multiply';
+ // No shadow.
+
+ ctx.beginLayer();
+
+ // Enable compositing in the layer to validate that draw calls in the layer
+ // won't individually composite with the background.
+ ctx.globalCompositeOperation = 'screen';
+
+ 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();
+ </script>
+</span>
+
+</div>
diff --git a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.blending.shadow-expected.html b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.blending.shadow-expected.html
deleted file mode 100644
index 6f969074f9..0000000000
--- a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.blending.shadow-expected.html
+++ /dev/null
@@ -1,35 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<title>Canvas test: 2d.layer.global-states.blending.shadow</title>
-<h1>2d.layer.global-states.blending.shadow</h1>
-<p class="desc">Checks that layers correctly use global render states.</p>
-<canvas id="canvas" width="200" height="200">
- <p class="fallback">FAIL (fallback content)</p>
-</canvas>
-<script>
- const canvas = document.getElementById("canvas");
- const ctx = canvas.getContext('2d');
-
- ctx.fillStyle = 'rgba(0, 0, 255, 1)';
-
- var circle = new Path2D();
- circle.arc(90, 90, 45, 0, 2 * Math.PI);
- ctx.fill(circle);
-
- ctx.globalCompositeOperation = 'multiply';
- ctx.shadowOffsetX = -10;
- ctx.shadowOffsetY = 10;
- ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
- ctx.shadowBlur = 3;
-
- canvas2 = document.createElement("canvas");
- ctx2 = canvas2.getContext("2d");
-
- ctx2.globalCompositeOperation = 'screen';
- ctx2.fillStyle = 'rgba(225, 0, 0, 1)';
- ctx2.fillRect(50, 50, 75, 50);
- ctx2.fillStyle = 'rgba(0, 255, 0, 1)';
- ctx2.fillRect(70, 70, 75, 50);
-
- ctx.drawImage(canvas2, 0, 0);
-</script>
diff --git a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.blending.shadow.html b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.blending.shadow.html
deleted file mode 100644
index 51926d76d8..0000000000
--- a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.blending.shadow.html
+++ /dev/null
@@ -1,38 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<link rel="match" href="2d.layer.global-states.blending.shadow-expected.html">
-<title>Canvas test: 2d.layer.global-states.blending.shadow</title>
-<h1>2d.layer.global-states.blending.shadow</h1>
-<p class="desc">Checks that layers correctly use global render states.</p>
-<canvas id="canvas" width="200" height="200">
- <p class="fallback">FAIL (fallback content)</p>
-</canvas>
-<script>
- const canvas = document.getElementById("canvas");
- const ctx = canvas.getContext('2d');
-
- ctx.fillStyle = 'rgba(0, 0, 255, 1)';
-
- var circle = new Path2D();
- circle.arc(90, 90, 45, 0, 2 * Math.PI);
- ctx.fill(circle);
-
- ctx.globalCompositeOperation = 'multiply';
- ctx.shadowOffsetX = -10;
- ctx.shadowOffsetY = 10;
- ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
- ctx.shadowBlur = 3;
-
- ctx.beginLayer();
-
- // Enable compositing in the layer to validate that draw calls in the layer
- // 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(0, 255, 0, 1)';
- ctx.fillRect(70, 70, 75, 50);
-
- ctx.endLayer();
-</script>
diff --git a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.blending.shadow.no-transform-expected.html b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.blending.shadow.no-transform-expected.html
new file mode 100644
index 0000000000..debbd430c4
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.blending.shadow.no-transform-expected.html
@@ -0,0 +1,78 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<title>Canvas test: 2d.layer.global-states.blending.shadow.no-transform</title>
+<h1 style="font-size: 20px;">2d.layer.global-states.blending.shadow.no-transform</h1>
+<p class="desc">Checks that layers correctly use global render states.</p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(2, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>no-globalAlpha</div>
+ <canvas id="canvas0" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas0");
+ const ctx = canvas.getContext('2d');
+
+ // No transform.
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ // No globalAlpha.
+ ctx.globalCompositeOperation = 'multiply';
+ ctx.shadowOffsetX = -7;
+ ctx.shadowOffsetY = 7;
+ ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
+ ctx.shadowBlur = 3;
+
+ const canvas2 = document.createElement("canvas");
+ const ctx2 = canvas2.getContext("2d");
+
+ ctx2.globalCompositeOperation = 'screen';
+ ctx2.fillStyle = 'rgba(255, 0, 0, 1)';
+ ctx2.fillRect(10, 25, 40, 50);
+ ctx2.fillStyle = 'rgba(0, 255, 0, 1)';
+ ctx2.fillRect(30, 5, 50, 40);
+
+ ctx.drawImage(canvas2, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>globalAlpha</div>
+ <canvas id="canvas1" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas1");
+ const ctx = canvas.getContext('2d');
+
+ // No transform.
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ ctx.globalAlpha = 0.75;
+ ctx.globalCompositeOperation = 'multiply';
+ ctx.shadowOffsetX = -7;
+ ctx.shadowOffsetY = 7;
+ ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
+ ctx.shadowBlur = 3;
+
+ const canvas2 = document.createElement("canvas");
+ const ctx2 = canvas2.getContext("2d");
+
+ ctx2.globalCompositeOperation = 'screen';
+ ctx2.fillStyle = 'rgba(255, 0, 0, 1)';
+ ctx2.fillRect(10, 25, 40, 50);
+ ctx2.fillStyle = 'rgba(0, 255, 0, 1)';
+ ctx2.fillRect(30, 5, 50, 40);
+
+ ctx.drawImage(canvas2, 0, 0);
+ </script>
+</span>
+
+</div>
diff --git a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.blending.shadow.no-transform.html b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.blending.shadow.no-transform.html
new file mode 100644
index 0000000000..e0b8e45b51
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.blending.shadow.no-transform.html
@@ -0,0 +1,83 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<link rel="match" href="2d.layer.global-states.blending.shadow.no-transform-expected.html">
+<title>Canvas test: 2d.layer.global-states.blending.shadow.no-transform</title>
+<h1 style="font-size: 20px;">2d.layer.global-states.blending.shadow.no-transform</h1>
+<p class="desc">Checks that layers correctly use global render states.</p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(2, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>no-globalAlpha</div>
+ <canvas id="canvas0" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas0");
+ const ctx = canvas.getContext('2d');
+
+ // No transform.
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ // No globalAlpha.
+ ctx.globalCompositeOperation = 'multiply';
+ ctx.shadowOffsetX = -7;
+ ctx.shadowOffsetY = 7;
+ ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
+ ctx.shadowBlur = 3;
+
+ ctx.beginLayer();
+
+ // Enable compositing in the layer to validate that draw calls in the layer
+ // won't individually composite with the background.
+ ctx.globalCompositeOperation = 'screen';
+
+ 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();
+ </script>
+</span>
+
+<span>
+ <div>globalAlpha</div>
+ <canvas id="canvas1" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas1");
+ const ctx = canvas.getContext('2d');
+
+ // No transform.
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ ctx.globalAlpha = 0.75;
+ ctx.globalCompositeOperation = 'multiply';
+ ctx.shadowOffsetX = -7;
+ ctx.shadowOffsetY = 7;
+ ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
+ ctx.shadowBlur = 3;
+
+ ctx.beginLayer();
+
+ // Enable compositing in the layer to validate that draw calls in the layer
+ // won't individually composite with the background.
+ ctx.globalCompositeOperation = 'screen';
+
+ 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();
+ </script>
+</span>
+
+</div>
diff --git a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.blending.shadow.rotation-expected.html b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.blending.shadow.rotation-expected.html
new file mode 100644
index 0000000000..75a55e591b
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.blending.shadow.rotation-expected.html
@@ -0,0 +1,82 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<title>Canvas test: 2d.layer.global-states.blending.shadow.rotation</title>
+<h1 style="font-size: 20px;">2d.layer.global-states.blending.shadow.rotation</h1>
+<p class="desc">Checks that layers correctly use global render states.</p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(2, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>no-globalAlpha</div>
+ <canvas id="canvas0" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas0");
+ const ctx = canvas.getContext('2d');
+
+ ctx.translate(50, 40);
+ ctx.rotate(Math.PI);
+ ctx.translate(-45, -45);
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ // No globalAlpha.
+ ctx.globalCompositeOperation = 'multiply';
+ ctx.shadowOffsetX = -7;
+ ctx.shadowOffsetY = 7;
+ ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
+ ctx.shadowBlur = 3;
+
+ const canvas2 = document.createElement("canvas");
+ const ctx2 = canvas2.getContext("2d");
+
+ ctx2.globalCompositeOperation = 'screen';
+ ctx2.fillStyle = 'rgba(255, 0, 0, 1)';
+ ctx2.fillRect(10, 25, 40, 50);
+ ctx2.fillStyle = 'rgba(0, 255, 0, 1)';
+ ctx2.fillRect(30, 5, 50, 40);
+
+ ctx.drawImage(canvas2, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>globalAlpha</div>
+ <canvas id="canvas1" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas1");
+ const ctx = canvas.getContext('2d');
+
+ ctx.translate(50, 40);
+ ctx.rotate(Math.PI);
+ ctx.translate(-45, -45);
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ ctx.globalAlpha = 0.75;
+ ctx.globalCompositeOperation = 'multiply';
+ ctx.shadowOffsetX = -7;
+ ctx.shadowOffsetY = 7;
+ ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
+ ctx.shadowBlur = 3;
+
+ const canvas2 = document.createElement("canvas");
+ const ctx2 = canvas2.getContext("2d");
+
+ ctx2.globalCompositeOperation = 'screen';
+ ctx2.fillStyle = 'rgba(255, 0, 0, 1)';
+ ctx2.fillRect(10, 25, 40, 50);
+ ctx2.fillStyle = 'rgba(0, 255, 0, 1)';
+ ctx2.fillRect(30, 5, 50, 40);
+
+ ctx.drawImage(canvas2, 0, 0);
+ </script>
+</span>
+
+</div>
diff --git a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.blending.shadow.rotation.html b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.blending.shadow.rotation.html
new file mode 100644
index 0000000000..f3891369c9
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.blending.shadow.rotation.html
@@ -0,0 +1,87 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<link rel="match" href="2d.layer.global-states.blending.shadow.rotation-expected.html">
+<title>Canvas test: 2d.layer.global-states.blending.shadow.rotation</title>
+<h1 style="font-size: 20px;">2d.layer.global-states.blending.shadow.rotation</h1>
+<p class="desc">Checks that layers correctly use global render states.</p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(2, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>no-globalAlpha</div>
+ <canvas id="canvas0" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas0");
+ const ctx = canvas.getContext('2d');
+
+ ctx.translate(50, 40);
+ ctx.rotate(Math.PI);
+ ctx.translate(-45, -45);
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ // No globalAlpha.
+ ctx.globalCompositeOperation = 'multiply';
+ ctx.shadowOffsetX = -7;
+ ctx.shadowOffsetY = 7;
+ ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
+ ctx.shadowBlur = 3;
+
+ ctx.beginLayer();
+
+ // Enable compositing in the layer to validate that draw calls in the layer
+ // won't individually composite with the background.
+ ctx.globalCompositeOperation = 'screen';
+
+ 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();
+ </script>
+</span>
+
+<span>
+ <div>globalAlpha</div>
+ <canvas id="canvas1" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas1");
+ const ctx = canvas.getContext('2d');
+
+ ctx.translate(50, 40);
+ ctx.rotate(Math.PI);
+ ctx.translate(-45, -45);
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ ctx.globalAlpha = 0.75;
+ ctx.globalCompositeOperation = 'multiply';
+ ctx.shadowOffsetX = -7;
+ ctx.shadowOffsetY = 7;
+ ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
+ ctx.shadowBlur = 3;
+
+ ctx.beginLayer();
+
+ // Enable compositing in the layer to validate that draw calls in the layer
+ // won't individually composite with the background.
+ ctx.globalCompositeOperation = 'screen';
+
+ 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();
+ </script>
+</span>
+
+</div>
diff --git a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.composite-expected.html b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.composite-expected.html
deleted file mode 100644
index ed7669c4cf..0000000000
--- a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.composite-expected.html
+++ /dev/null
@@ -1,31 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<title>Canvas test: 2d.layer.global-states.composite</title>
-<h1>2d.layer.global-states.composite</h1>
-<p class="desc">Checks that layers correctly use global render states.</p>
-<canvas id="canvas" width="200" height="200">
- <p class="fallback">FAIL (fallback content)</p>
-</canvas>
-<script>
- const canvas = document.getElementById("canvas");
- const ctx = canvas.getContext('2d');
-
- ctx.fillStyle = 'rgba(0, 0, 255, 1)';
-
- var circle = new Path2D();
- circle.arc(90, 90, 45, 0, 2 * Math.PI);
- ctx.fill(circle);
-
- ctx.globalCompositeOperation = 'source-in';
-
- canvas2 = document.createElement("canvas");
- ctx2 = canvas2.getContext("2d");
-
- ctx2.globalCompositeOperation = 'screen';
- ctx2.fillStyle = 'rgba(225, 0, 0, 1)';
- ctx2.fillRect(50, 50, 75, 50);
- ctx2.fillStyle = 'rgba(0, 255, 0, 1)';
- ctx2.fillRect(70, 70, 75, 50);
-
- ctx.drawImage(canvas2, 0, 0);
-</script>
diff --git a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.composite.html b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.composite.html
deleted file mode 100644
index 898d149924..0000000000
--- a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.composite.html
+++ /dev/null
@@ -1,34 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<link rel="match" href="2d.layer.global-states.composite-expected.html">
-<title>Canvas test: 2d.layer.global-states.composite</title>
-<h1>2d.layer.global-states.composite</h1>
-<p class="desc">Checks that layers correctly use global render states.</p>
-<canvas id="canvas" width="200" height="200">
- <p class="fallback">FAIL (fallback content)</p>
-</canvas>
-<script>
- const canvas = document.getElementById("canvas");
- const ctx = canvas.getContext('2d');
-
- ctx.fillStyle = 'rgba(0, 0, 255, 1)';
-
- var circle = new Path2D();
- circle.arc(90, 90, 45, 0, 2 * Math.PI);
- ctx.fill(circle);
-
- ctx.globalCompositeOperation = 'source-in';
-
- ctx.beginLayer();
-
- // Enable compositing in the layer to validate that draw calls in the layer
- // 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(0, 255, 0, 1)';
- ctx.fillRect(70, 70, 75, 50);
-
- ctx.endLayer();
-</script>
diff --git a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.composite.no-shadow.no-transform-expected.html b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.composite.no-shadow.no-transform-expected.html
new file mode 100644
index 0000000000..cf87559582
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.composite.no-shadow.no-transform-expected.html
@@ -0,0 +1,72 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<title>Canvas test: 2d.layer.global-states.composite.no-shadow.no-transform</title>
+<h1 style="font-size: 20px;">2d.layer.global-states.composite.no-shadow.no-transform</h1>
+<p class="desc">Checks that layers correctly use global render states.</p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(2, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>no-globalAlpha</div>
+ <canvas id="canvas0" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas0");
+ const ctx = canvas.getContext('2d');
+
+ // No transform.
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ // No globalAlpha.
+ ctx.globalCompositeOperation = 'source-in';
+ // No shadow.
+
+ const canvas2 = document.createElement("canvas");
+ const ctx2 = canvas2.getContext("2d");
+
+ ctx2.globalCompositeOperation = 'screen';
+ ctx2.fillStyle = 'rgba(255, 0, 0, 1)';
+ ctx2.fillRect(10, 25, 40, 50);
+ ctx2.fillStyle = 'rgba(0, 255, 0, 1)';
+ ctx2.fillRect(30, 5, 50, 40);
+
+ ctx.drawImage(canvas2, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>globalAlpha</div>
+ <canvas id="canvas1" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas1");
+ const ctx = canvas.getContext('2d');
+
+ // No transform.
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ ctx.globalAlpha = 0.75;
+ ctx.globalCompositeOperation = 'source-in';
+ // No shadow.
+
+ const canvas2 = document.createElement("canvas");
+ const ctx2 = canvas2.getContext("2d");
+
+ ctx2.globalCompositeOperation = 'screen';
+ ctx2.fillStyle = 'rgba(255, 0, 0, 1)';
+ ctx2.fillRect(10, 25, 40, 50);
+ ctx2.fillStyle = 'rgba(0, 255, 0, 1)';
+ ctx2.fillRect(30, 5, 50, 40);
+
+ ctx.drawImage(canvas2, 0, 0);
+ </script>
+</span>
+
+</div>
diff --git a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.composite.no-shadow.no-transform.html b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.composite.no-shadow.no-transform.html
new file mode 100644
index 0000000000..195905e16b
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.composite.no-shadow.no-transform.html
@@ -0,0 +1,77 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<link rel="match" href="2d.layer.global-states.composite.no-shadow.no-transform-expected.html">
+<title>Canvas test: 2d.layer.global-states.composite.no-shadow.no-transform</title>
+<h1 style="font-size: 20px;">2d.layer.global-states.composite.no-shadow.no-transform</h1>
+<p class="desc">Checks that layers correctly use global render states.</p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(2, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>no-globalAlpha</div>
+ <canvas id="canvas0" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas0");
+ const ctx = canvas.getContext('2d');
+
+ // No transform.
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ // No globalAlpha.
+ ctx.globalCompositeOperation = 'source-in';
+ // No shadow.
+
+ ctx.beginLayer();
+
+ // Enable compositing in the layer to validate that draw calls in the layer
+ // won't individually composite with the background.
+ ctx.globalCompositeOperation = 'screen';
+
+ 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();
+ </script>
+</span>
+
+<span>
+ <div>globalAlpha</div>
+ <canvas id="canvas1" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas1");
+ const ctx = canvas.getContext('2d');
+
+ // No transform.
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ ctx.globalAlpha = 0.75;
+ ctx.globalCompositeOperation = 'source-in';
+ // No shadow.
+
+ ctx.beginLayer();
+
+ // Enable compositing in the layer to validate that draw calls in the layer
+ // won't individually composite with the background.
+ ctx.globalCompositeOperation = 'screen';
+
+ 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();
+ </script>
+</span>
+
+</div>
diff --git a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.composite.no-shadow.rotation-expected.html b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.composite.no-shadow.rotation-expected.html
new file mode 100644
index 0000000000..2f9bb208fb
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.composite.no-shadow.rotation-expected.html
@@ -0,0 +1,76 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<title>Canvas test: 2d.layer.global-states.composite.no-shadow.rotation</title>
+<h1 style="font-size: 20px;">2d.layer.global-states.composite.no-shadow.rotation</h1>
+<p class="desc">Checks that layers correctly use global render states.</p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(2, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>no-globalAlpha</div>
+ <canvas id="canvas0" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas0");
+ const ctx = canvas.getContext('2d');
+
+ ctx.translate(50, 40);
+ ctx.rotate(Math.PI);
+ ctx.translate(-45, -45);
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ // No globalAlpha.
+ ctx.globalCompositeOperation = 'source-in';
+ // No shadow.
+
+ const canvas2 = document.createElement("canvas");
+ const ctx2 = canvas2.getContext("2d");
+
+ ctx2.globalCompositeOperation = 'screen';
+ ctx2.fillStyle = 'rgba(255, 0, 0, 1)';
+ ctx2.fillRect(10, 25, 40, 50);
+ ctx2.fillStyle = 'rgba(0, 255, 0, 1)';
+ ctx2.fillRect(30, 5, 50, 40);
+
+ ctx.drawImage(canvas2, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>globalAlpha</div>
+ <canvas id="canvas1" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas1");
+ const ctx = canvas.getContext('2d');
+
+ ctx.translate(50, 40);
+ ctx.rotate(Math.PI);
+ ctx.translate(-45, -45);
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ ctx.globalAlpha = 0.75;
+ ctx.globalCompositeOperation = 'source-in';
+ // No shadow.
+
+ const canvas2 = document.createElement("canvas");
+ const ctx2 = canvas2.getContext("2d");
+
+ ctx2.globalCompositeOperation = 'screen';
+ ctx2.fillStyle = 'rgba(255, 0, 0, 1)';
+ ctx2.fillRect(10, 25, 40, 50);
+ ctx2.fillStyle = 'rgba(0, 255, 0, 1)';
+ ctx2.fillRect(30, 5, 50, 40);
+
+ ctx.drawImage(canvas2, 0, 0);
+ </script>
+</span>
+
+</div>
diff --git a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.composite.no-shadow.rotation.html b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.composite.no-shadow.rotation.html
new file mode 100644
index 0000000000..905fd7637b
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.composite.no-shadow.rotation.html
@@ -0,0 +1,81 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<link rel="match" href="2d.layer.global-states.composite.no-shadow.rotation-expected.html">
+<title>Canvas test: 2d.layer.global-states.composite.no-shadow.rotation</title>
+<h1 style="font-size: 20px;">2d.layer.global-states.composite.no-shadow.rotation</h1>
+<p class="desc">Checks that layers correctly use global render states.</p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(2, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>no-globalAlpha</div>
+ <canvas id="canvas0" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas0");
+ const ctx = canvas.getContext('2d');
+
+ ctx.translate(50, 40);
+ ctx.rotate(Math.PI);
+ ctx.translate(-45, -45);
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ // No globalAlpha.
+ ctx.globalCompositeOperation = 'source-in';
+ // No shadow.
+
+ ctx.beginLayer();
+
+ // Enable compositing in the layer to validate that draw calls in the layer
+ // won't individually composite with the background.
+ ctx.globalCompositeOperation = 'screen';
+
+ 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();
+ </script>
+</span>
+
+<span>
+ <div>globalAlpha</div>
+ <canvas id="canvas1" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas1");
+ const ctx = canvas.getContext('2d');
+
+ ctx.translate(50, 40);
+ ctx.rotate(Math.PI);
+ ctx.translate(-45, -45);
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ ctx.globalAlpha = 0.75;
+ ctx.globalCompositeOperation = 'source-in';
+ // No shadow.
+
+ ctx.beginLayer();
+
+ // Enable compositing in the layer to validate that draw calls in the layer
+ // won't individually composite with the background.
+ ctx.globalCompositeOperation = 'screen';
+
+ 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();
+ </script>
+</span>
+
+</div>
diff --git a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.composite.shadow-expected.html b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.composite.shadow-expected.html
deleted file mode 100644
index b687c27f47..0000000000
--- a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.composite.shadow-expected.html
+++ /dev/null
@@ -1,35 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<title>Canvas test: 2d.layer.global-states.composite.shadow</title>
-<h1>2d.layer.global-states.composite.shadow</h1>
-<p class="desc">Checks that layers correctly use global render states.</p>
-<canvas id="canvas" width="200" height="200">
- <p class="fallback">FAIL (fallback content)</p>
-</canvas>
-<script>
- const canvas = document.getElementById("canvas");
- const ctx = canvas.getContext('2d');
-
- ctx.fillStyle = 'rgba(0, 0, 255, 1)';
-
- var circle = new Path2D();
- circle.arc(90, 90, 45, 0, 2 * Math.PI);
- ctx.fill(circle);
-
- ctx.globalCompositeOperation = 'source-in';
- ctx.shadowOffsetX = -10;
- ctx.shadowOffsetY = 10;
- ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
- ctx.shadowBlur = 3;
-
- canvas2 = document.createElement("canvas");
- ctx2 = canvas2.getContext("2d");
-
- ctx2.globalCompositeOperation = 'screen';
- ctx2.fillStyle = 'rgba(225, 0, 0, 1)';
- ctx2.fillRect(50, 50, 75, 50);
- ctx2.fillStyle = 'rgba(0, 255, 0, 1)';
- ctx2.fillRect(70, 70, 75, 50);
-
- ctx.drawImage(canvas2, 0, 0);
-</script>
diff --git a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.composite.shadow.html b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.composite.shadow.html
deleted file mode 100644
index c563a57b76..0000000000
--- a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.composite.shadow.html
+++ /dev/null
@@ -1,38 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<link rel="match" href="2d.layer.global-states.composite.shadow-expected.html">
-<title>Canvas test: 2d.layer.global-states.composite.shadow</title>
-<h1>2d.layer.global-states.composite.shadow</h1>
-<p class="desc">Checks that layers correctly use global render states.</p>
-<canvas id="canvas" width="200" height="200">
- <p class="fallback">FAIL (fallback content)</p>
-</canvas>
-<script>
- const canvas = document.getElementById("canvas");
- const ctx = canvas.getContext('2d');
-
- ctx.fillStyle = 'rgba(0, 0, 255, 1)';
-
- var circle = new Path2D();
- circle.arc(90, 90, 45, 0, 2 * Math.PI);
- ctx.fill(circle);
-
- ctx.globalCompositeOperation = 'source-in';
- ctx.shadowOffsetX = -10;
- ctx.shadowOffsetY = 10;
- ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
- ctx.shadowBlur = 3;
-
- ctx.beginLayer();
-
- // Enable compositing in the layer to validate that draw calls in the layer
- // 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(0, 255, 0, 1)';
- ctx.fillRect(70, 70, 75, 50);
-
- ctx.endLayer();
-</script>
diff --git a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.composite.shadow.no-transform-expected.html b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.composite.shadow.no-transform-expected.html
new file mode 100644
index 0000000000..2b4436806a
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.composite.shadow.no-transform-expected.html
@@ -0,0 +1,78 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<title>Canvas test: 2d.layer.global-states.composite.shadow.no-transform</title>
+<h1 style="font-size: 20px;">2d.layer.global-states.composite.shadow.no-transform</h1>
+<p class="desc">Checks that layers correctly use global render states.</p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(2, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>no-globalAlpha</div>
+ <canvas id="canvas0" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas0");
+ const ctx = canvas.getContext('2d');
+
+ // No transform.
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ // No globalAlpha.
+ ctx.globalCompositeOperation = 'source-in';
+ ctx.shadowOffsetX = -7;
+ ctx.shadowOffsetY = 7;
+ ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
+ ctx.shadowBlur = 3;
+
+ const canvas2 = document.createElement("canvas");
+ const ctx2 = canvas2.getContext("2d");
+
+ ctx2.globalCompositeOperation = 'screen';
+ ctx2.fillStyle = 'rgba(255, 0, 0, 1)';
+ ctx2.fillRect(10, 25, 40, 50);
+ ctx2.fillStyle = 'rgba(0, 255, 0, 1)';
+ ctx2.fillRect(30, 5, 50, 40);
+
+ ctx.drawImage(canvas2, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>globalAlpha</div>
+ <canvas id="canvas1" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas1");
+ const ctx = canvas.getContext('2d');
+
+ // No transform.
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ ctx.globalAlpha = 0.75;
+ ctx.globalCompositeOperation = 'source-in';
+ ctx.shadowOffsetX = -7;
+ ctx.shadowOffsetY = 7;
+ ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
+ ctx.shadowBlur = 3;
+
+ const canvas2 = document.createElement("canvas");
+ const ctx2 = canvas2.getContext("2d");
+
+ ctx2.globalCompositeOperation = 'screen';
+ ctx2.fillStyle = 'rgba(255, 0, 0, 1)';
+ ctx2.fillRect(10, 25, 40, 50);
+ ctx2.fillStyle = 'rgba(0, 255, 0, 1)';
+ ctx2.fillRect(30, 5, 50, 40);
+
+ ctx.drawImage(canvas2, 0, 0);
+ </script>
+</span>
+
+</div>
diff --git a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.composite.shadow.no-transform.html b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.composite.shadow.no-transform.html
new file mode 100644
index 0000000000..df008cf12e
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.composite.shadow.no-transform.html
@@ -0,0 +1,83 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<link rel="match" href="2d.layer.global-states.composite.shadow.no-transform-expected.html">
+<title>Canvas test: 2d.layer.global-states.composite.shadow.no-transform</title>
+<h1 style="font-size: 20px;">2d.layer.global-states.composite.shadow.no-transform</h1>
+<p class="desc">Checks that layers correctly use global render states.</p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(2, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>no-globalAlpha</div>
+ <canvas id="canvas0" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas0");
+ const ctx = canvas.getContext('2d');
+
+ // No transform.
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ // No globalAlpha.
+ ctx.globalCompositeOperation = 'source-in';
+ ctx.shadowOffsetX = -7;
+ ctx.shadowOffsetY = 7;
+ ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
+ ctx.shadowBlur = 3;
+
+ ctx.beginLayer();
+
+ // Enable compositing in the layer to validate that draw calls in the layer
+ // won't individually composite with the background.
+ ctx.globalCompositeOperation = 'screen';
+
+ 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();
+ </script>
+</span>
+
+<span>
+ <div>globalAlpha</div>
+ <canvas id="canvas1" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas1");
+ const ctx = canvas.getContext('2d');
+
+ // No transform.
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ ctx.globalAlpha = 0.75;
+ ctx.globalCompositeOperation = 'source-in';
+ ctx.shadowOffsetX = -7;
+ ctx.shadowOffsetY = 7;
+ ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
+ ctx.shadowBlur = 3;
+
+ ctx.beginLayer();
+
+ // Enable compositing in the layer to validate that draw calls in the layer
+ // won't individually composite with the background.
+ ctx.globalCompositeOperation = 'screen';
+
+ 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();
+ </script>
+</span>
+
+</div>
diff --git a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.composite.shadow.rotation-expected.html b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.composite.shadow.rotation-expected.html
new file mode 100644
index 0000000000..da144975a5
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.composite.shadow.rotation-expected.html
@@ -0,0 +1,82 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<title>Canvas test: 2d.layer.global-states.composite.shadow.rotation</title>
+<h1 style="font-size: 20px;">2d.layer.global-states.composite.shadow.rotation</h1>
+<p class="desc">Checks that layers correctly use global render states.</p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(2, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>no-globalAlpha</div>
+ <canvas id="canvas0" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas0");
+ const ctx = canvas.getContext('2d');
+
+ ctx.translate(50, 40);
+ ctx.rotate(Math.PI);
+ ctx.translate(-45, -45);
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ // No globalAlpha.
+ ctx.globalCompositeOperation = 'source-in';
+ ctx.shadowOffsetX = -7;
+ ctx.shadowOffsetY = 7;
+ ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
+ ctx.shadowBlur = 3;
+
+ const canvas2 = document.createElement("canvas");
+ const ctx2 = canvas2.getContext("2d");
+
+ ctx2.globalCompositeOperation = 'screen';
+ ctx2.fillStyle = 'rgba(255, 0, 0, 1)';
+ ctx2.fillRect(10, 25, 40, 50);
+ ctx2.fillStyle = 'rgba(0, 255, 0, 1)';
+ ctx2.fillRect(30, 5, 50, 40);
+
+ ctx.drawImage(canvas2, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>globalAlpha</div>
+ <canvas id="canvas1" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas1");
+ const ctx = canvas.getContext('2d');
+
+ ctx.translate(50, 40);
+ ctx.rotate(Math.PI);
+ ctx.translate(-45, -45);
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ ctx.globalAlpha = 0.75;
+ ctx.globalCompositeOperation = 'source-in';
+ ctx.shadowOffsetX = -7;
+ ctx.shadowOffsetY = 7;
+ ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
+ ctx.shadowBlur = 3;
+
+ const canvas2 = document.createElement("canvas");
+ const ctx2 = canvas2.getContext("2d");
+
+ ctx2.globalCompositeOperation = 'screen';
+ ctx2.fillStyle = 'rgba(255, 0, 0, 1)';
+ ctx2.fillRect(10, 25, 40, 50);
+ ctx2.fillStyle = 'rgba(0, 255, 0, 1)';
+ ctx2.fillRect(30, 5, 50, 40);
+
+ ctx.drawImage(canvas2, 0, 0);
+ </script>
+</span>
+
+</div>
diff --git a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.composite.shadow.rotation.html b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.composite.shadow.rotation.html
new file mode 100644
index 0000000000..99e1d95443
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.composite.shadow.rotation.html
@@ -0,0 +1,87 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<link rel="match" href="2d.layer.global-states.composite.shadow.rotation-expected.html">
+<title>Canvas test: 2d.layer.global-states.composite.shadow.rotation</title>
+<h1 style="font-size: 20px;">2d.layer.global-states.composite.shadow.rotation</h1>
+<p class="desc">Checks that layers correctly use global render states.</p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(2, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>no-globalAlpha</div>
+ <canvas id="canvas0" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas0");
+ const ctx = canvas.getContext('2d');
+
+ ctx.translate(50, 40);
+ ctx.rotate(Math.PI);
+ ctx.translate(-45, -45);
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ // No globalAlpha.
+ ctx.globalCompositeOperation = 'source-in';
+ ctx.shadowOffsetX = -7;
+ ctx.shadowOffsetY = 7;
+ ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
+ ctx.shadowBlur = 3;
+
+ ctx.beginLayer();
+
+ // Enable compositing in the layer to validate that draw calls in the layer
+ // won't individually composite with the background.
+ ctx.globalCompositeOperation = 'screen';
+
+ 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();
+ </script>
+</span>
+
+<span>
+ <div>globalAlpha</div>
+ <canvas id="canvas1" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas1");
+ const ctx = canvas.getContext('2d');
+
+ ctx.translate(50, 40);
+ ctx.rotate(Math.PI);
+ ctx.translate(-45, -45);
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ ctx.globalAlpha = 0.75;
+ ctx.globalCompositeOperation = 'source-in';
+ ctx.shadowOffsetX = -7;
+ ctx.shadowOffsetY = 7;
+ ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
+ ctx.shadowBlur = 3;
+
+ ctx.beginLayer();
+
+ // Enable compositing in the layer to validate that draw calls in the layer
+ // won't individually composite with the background.
+ ctx.globalCompositeOperation = 'screen';
+
+ 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();
+ </script>
+</span>
+
+</div>
diff --git a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.copy.no-shadow.no-transform-expected.html b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.copy.no-shadow.no-transform-expected.html
new file mode 100644
index 0000000000..489d432282
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.copy.no-shadow.no-transform-expected.html
@@ -0,0 +1,72 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<title>Canvas test: 2d.layer.global-states.copy.no-shadow.no-transform</title>
+<h1 style="font-size: 20px;">2d.layer.global-states.copy.no-shadow.no-transform</h1>
+<p class="desc">Checks that layers correctly use global render states.</p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(2, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>no-globalAlpha</div>
+ <canvas id="canvas0" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas0");
+ const ctx = canvas.getContext('2d');
+
+ // No transform.
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ // No globalAlpha.
+ ctx.globalCompositeOperation = 'copy';
+ // No shadow.
+
+ const canvas2 = document.createElement("canvas");
+ const ctx2 = canvas2.getContext("2d");
+
+ ctx2.globalCompositeOperation = 'screen';
+ ctx2.fillStyle = 'rgba(255, 0, 0, 1)';
+ ctx2.fillRect(10, 25, 40, 50);
+ ctx2.fillStyle = 'rgba(0, 255, 0, 1)';
+ ctx2.fillRect(30, 5, 50, 40);
+
+ ctx.drawImage(canvas2, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>globalAlpha</div>
+ <canvas id="canvas1" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas1");
+ const ctx = canvas.getContext('2d');
+
+ // No transform.
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ ctx.globalAlpha = 0.75;
+ ctx.globalCompositeOperation = 'copy';
+ // No shadow.
+
+ const canvas2 = document.createElement("canvas");
+ const ctx2 = canvas2.getContext("2d");
+
+ ctx2.globalCompositeOperation = 'screen';
+ ctx2.fillStyle = 'rgba(255, 0, 0, 1)';
+ ctx2.fillRect(10, 25, 40, 50);
+ ctx2.fillStyle = 'rgba(0, 255, 0, 1)';
+ ctx2.fillRect(30, 5, 50, 40);
+
+ ctx.drawImage(canvas2, 0, 0);
+ </script>
+</span>
+
+</div>
diff --git a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.copy.no-shadow.no-transform.html b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.copy.no-shadow.no-transform.html
new file mode 100644
index 0000000000..1720f20589
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.copy.no-shadow.no-transform.html
@@ -0,0 +1,77 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<link rel="match" href="2d.layer.global-states.copy.no-shadow.no-transform-expected.html">
+<title>Canvas test: 2d.layer.global-states.copy.no-shadow.no-transform</title>
+<h1 style="font-size: 20px;">2d.layer.global-states.copy.no-shadow.no-transform</h1>
+<p class="desc">Checks that layers correctly use global render states.</p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(2, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>no-globalAlpha</div>
+ <canvas id="canvas0" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas0");
+ const ctx = canvas.getContext('2d');
+
+ // No transform.
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ // No globalAlpha.
+ ctx.globalCompositeOperation = 'copy';
+ // No shadow.
+
+ ctx.beginLayer();
+
+ // Enable compositing in the layer to validate that draw calls in the layer
+ // won't individually composite with the background.
+ ctx.globalCompositeOperation = 'screen';
+
+ 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();
+ </script>
+</span>
+
+<span>
+ <div>globalAlpha</div>
+ <canvas id="canvas1" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas1");
+ const ctx = canvas.getContext('2d');
+
+ // No transform.
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ ctx.globalAlpha = 0.75;
+ ctx.globalCompositeOperation = 'copy';
+ // No shadow.
+
+ ctx.beginLayer();
+
+ // Enable compositing in the layer to validate that draw calls in the layer
+ // won't individually composite with the background.
+ ctx.globalCompositeOperation = 'screen';
+
+ 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();
+ </script>
+</span>
+
+</div>
diff --git a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.copy.no-shadow.rotation-expected.html b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.copy.no-shadow.rotation-expected.html
new file mode 100644
index 0000000000..63913ffb05
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.copy.no-shadow.rotation-expected.html
@@ -0,0 +1,76 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<title>Canvas test: 2d.layer.global-states.copy.no-shadow.rotation</title>
+<h1 style="font-size: 20px;">2d.layer.global-states.copy.no-shadow.rotation</h1>
+<p class="desc">Checks that layers correctly use global render states.</p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(2, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>no-globalAlpha</div>
+ <canvas id="canvas0" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas0");
+ const ctx = canvas.getContext('2d');
+
+ ctx.translate(50, 40);
+ ctx.rotate(Math.PI);
+ ctx.translate(-45, -45);
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ // No globalAlpha.
+ ctx.globalCompositeOperation = 'copy';
+ // No shadow.
+
+ const canvas2 = document.createElement("canvas");
+ const ctx2 = canvas2.getContext("2d");
+
+ ctx2.globalCompositeOperation = 'screen';
+ ctx2.fillStyle = 'rgba(255, 0, 0, 1)';
+ ctx2.fillRect(10, 25, 40, 50);
+ ctx2.fillStyle = 'rgba(0, 255, 0, 1)';
+ ctx2.fillRect(30, 5, 50, 40);
+
+ ctx.drawImage(canvas2, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>globalAlpha</div>
+ <canvas id="canvas1" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas1");
+ const ctx = canvas.getContext('2d');
+
+ ctx.translate(50, 40);
+ ctx.rotate(Math.PI);
+ ctx.translate(-45, -45);
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ ctx.globalAlpha = 0.75;
+ ctx.globalCompositeOperation = 'copy';
+ // No shadow.
+
+ const canvas2 = document.createElement("canvas");
+ const ctx2 = canvas2.getContext("2d");
+
+ ctx2.globalCompositeOperation = 'screen';
+ ctx2.fillStyle = 'rgba(255, 0, 0, 1)';
+ ctx2.fillRect(10, 25, 40, 50);
+ ctx2.fillStyle = 'rgba(0, 255, 0, 1)';
+ ctx2.fillRect(30, 5, 50, 40);
+
+ ctx.drawImage(canvas2, 0, 0);
+ </script>
+</span>
+
+</div>
diff --git a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.copy.no-shadow.rotation.html b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.copy.no-shadow.rotation.html
new file mode 100644
index 0000000000..87cd91bb12
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.copy.no-shadow.rotation.html
@@ -0,0 +1,81 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<link rel="match" href="2d.layer.global-states.copy.no-shadow.rotation-expected.html">
+<title>Canvas test: 2d.layer.global-states.copy.no-shadow.rotation</title>
+<h1 style="font-size: 20px;">2d.layer.global-states.copy.no-shadow.rotation</h1>
+<p class="desc">Checks that layers correctly use global render states.</p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(2, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>no-globalAlpha</div>
+ <canvas id="canvas0" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas0");
+ const ctx = canvas.getContext('2d');
+
+ ctx.translate(50, 40);
+ ctx.rotate(Math.PI);
+ ctx.translate(-45, -45);
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ // No globalAlpha.
+ ctx.globalCompositeOperation = 'copy';
+ // No shadow.
+
+ ctx.beginLayer();
+
+ // Enable compositing in the layer to validate that draw calls in the layer
+ // won't individually composite with the background.
+ ctx.globalCompositeOperation = 'screen';
+
+ 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();
+ </script>
+</span>
+
+<span>
+ <div>globalAlpha</div>
+ <canvas id="canvas1" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas1");
+ const ctx = canvas.getContext('2d');
+
+ ctx.translate(50, 40);
+ ctx.rotate(Math.PI);
+ ctx.translate(-45, -45);
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ ctx.globalAlpha = 0.75;
+ ctx.globalCompositeOperation = 'copy';
+ // No shadow.
+
+ ctx.beginLayer();
+
+ // Enable compositing in the layer to validate that draw calls in the layer
+ // won't individually composite with the background.
+ ctx.globalCompositeOperation = 'screen';
+
+ 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();
+ </script>
+</span>
+
+</div>
diff --git a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.copy.shadow.no-transform-expected.html b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.copy.shadow.no-transform-expected.html
new file mode 100644
index 0000000000..021581f892
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.copy.shadow.no-transform-expected.html
@@ -0,0 +1,78 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<title>Canvas test: 2d.layer.global-states.copy.shadow.no-transform</title>
+<h1 style="font-size: 20px;">2d.layer.global-states.copy.shadow.no-transform</h1>
+<p class="desc">Checks that layers correctly use global render states.</p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(2, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>no-globalAlpha</div>
+ <canvas id="canvas0" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas0");
+ const ctx = canvas.getContext('2d');
+
+ // No transform.
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ // No globalAlpha.
+ ctx.globalCompositeOperation = 'copy';
+ ctx.shadowOffsetX = -7;
+ ctx.shadowOffsetY = 7;
+ ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
+ ctx.shadowBlur = 3;
+
+ const canvas2 = document.createElement("canvas");
+ const ctx2 = canvas2.getContext("2d");
+
+ ctx2.globalCompositeOperation = 'screen';
+ ctx2.fillStyle = 'rgba(255, 0, 0, 1)';
+ ctx2.fillRect(10, 25, 40, 50);
+ ctx2.fillStyle = 'rgba(0, 255, 0, 1)';
+ ctx2.fillRect(30, 5, 50, 40);
+
+ ctx.drawImage(canvas2, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>globalAlpha</div>
+ <canvas id="canvas1" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas1");
+ const ctx = canvas.getContext('2d');
+
+ // No transform.
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ ctx.globalAlpha = 0.75;
+ ctx.globalCompositeOperation = 'copy';
+ ctx.shadowOffsetX = -7;
+ ctx.shadowOffsetY = 7;
+ ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
+ ctx.shadowBlur = 3;
+
+ const canvas2 = document.createElement("canvas");
+ const ctx2 = canvas2.getContext("2d");
+
+ ctx2.globalCompositeOperation = 'screen';
+ ctx2.fillStyle = 'rgba(255, 0, 0, 1)';
+ ctx2.fillRect(10, 25, 40, 50);
+ ctx2.fillStyle = 'rgba(0, 255, 0, 1)';
+ ctx2.fillRect(30, 5, 50, 40);
+
+ ctx.drawImage(canvas2, 0, 0);
+ </script>
+</span>
+
+</div>
diff --git a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.copy.shadow.no-transform.html b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.copy.shadow.no-transform.html
new file mode 100644
index 0000000000..e8d01065c1
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.copy.shadow.no-transform.html
@@ -0,0 +1,83 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<link rel="match" href="2d.layer.global-states.copy.shadow.no-transform-expected.html">
+<title>Canvas test: 2d.layer.global-states.copy.shadow.no-transform</title>
+<h1 style="font-size: 20px;">2d.layer.global-states.copy.shadow.no-transform</h1>
+<p class="desc">Checks that layers correctly use global render states.</p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(2, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>no-globalAlpha</div>
+ <canvas id="canvas0" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas0");
+ const ctx = canvas.getContext('2d');
+
+ // No transform.
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ // No globalAlpha.
+ ctx.globalCompositeOperation = 'copy';
+ ctx.shadowOffsetX = -7;
+ ctx.shadowOffsetY = 7;
+ ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
+ ctx.shadowBlur = 3;
+
+ ctx.beginLayer();
+
+ // Enable compositing in the layer to validate that draw calls in the layer
+ // won't individually composite with the background.
+ ctx.globalCompositeOperation = 'screen';
+
+ 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();
+ </script>
+</span>
+
+<span>
+ <div>globalAlpha</div>
+ <canvas id="canvas1" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas1");
+ const ctx = canvas.getContext('2d');
+
+ // No transform.
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ ctx.globalAlpha = 0.75;
+ ctx.globalCompositeOperation = 'copy';
+ ctx.shadowOffsetX = -7;
+ ctx.shadowOffsetY = 7;
+ ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
+ ctx.shadowBlur = 3;
+
+ ctx.beginLayer();
+
+ // Enable compositing in the layer to validate that draw calls in the layer
+ // won't individually composite with the background.
+ ctx.globalCompositeOperation = 'screen';
+
+ 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();
+ </script>
+</span>
+
+</div>
diff --git a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.copy.shadow.rotation-expected.html b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.copy.shadow.rotation-expected.html
new file mode 100644
index 0000000000..dd9a5c2a00
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.copy.shadow.rotation-expected.html
@@ -0,0 +1,82 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<title>Canvas test: 2d.layer.global-states.copy.shadow.rotation</title>
+<h1 style="font-size: 20px;">2d.layer.global-states.copy.shadow.rotation</h1>
+<p class="desc">Checks that layers correctly use global render states.</p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(2, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>no-globalAlpha</div>
+ <canvas id="canvas0" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas0");
+ const ctx = canvas.getContext('2d');
+
+ ctx.translate(50, 40);
+ ctx.rotate(Math.PI);
+ ctx.translate(-45, -45);
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ // No globalAlpha.
+ ctx.globalCompositeOperation = 'copy';
+ ctx.shadowOffsetX = -7;
+ ctx.shadowOffsetY = 7;
+ ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
+ ctx.shadowBlur = 3;
+
+ const canvas2 = document.createElement("canvas");
+ const ctx2 = canvas2.getContext("2d");
+
+ ctx2.globalCompositeOperation = 'screen';
+ ctx2.fillStyle = 'rgba(255, 0, 0, 1)';
+ ctx2.fillRect(10, 25, 40, 50);
+ ctx2.fillStyle = 'rgba(0, 255, 0, 1)';
+ ctx2.fillRect(30, 5, 50, 40);
+
+ ctx.drawImage(canvas2, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>globalAlpha</div>
+ <canvas id="canvas1" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas1");
+ const ctx = canvas.getContext('2d');
+
+ ctx.translate(50, 40);
+ ctx.rotate(Math.PI);
+ ctx.translate(-45, -45);
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ ctx.globalAlpha = 0.75;
+ ctx.globalCompositeOperation = 'copy';
+ ctx.shadowOffsetX = -7;
+ ctx.shadowOffsetY = 7;
+ ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
+ ctx.shadowBlur = 3;
+
+ const canvas2 = document.createElement("canvas");
+ const ctx2 = canvas2.getContext("2d");
+
+ ctx2.globalCompositeOperation = 'screen';
+ ctx2.fillStyle = 'rgba(255, 0, 0, 1)';
+ ctx2.fillRect(10, 25, 40, 50);
+ ctx2.fillStyle = 'rgba(0, 255, 0, 1)';
+ ctx2.fillRect(30, 5, 50, 40);
+
+ ctx.drawImage(canvas2, 0, 0);
+ </script>
+</span>
+
+</div>
diff --git a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.copy.shadow.rotation.html b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.copy.shadow.rotation.html
new file mode 100644
index 0000000000..5c7fa379f1
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.copy.shadow.rotation.html
@@ -0,0 +1,87 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<link rel="match" href="2d.layer.global-states.copy.shadow.rotation-expected.html">
+<title>Canvas test: 2d.layer.global-states.copy.shadow.rotation</title>
+<h1 style="font-size: 20px;">2d.layer.global-states.copy.shadow.rotation</h1>
+<p class="desc">Checks that layers correctly use global render states.</p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(2, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>no-globalAlpha</div>
+ <canvas id="canvas0" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas0");
+ const ctx = canvas.getContext('2d');
+
+ ctx.translate(50, 40);
+ ctx.rotate(Math.PI);
+ ctx.translate(-45, -45);
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ // No globalAlpha.
+ ctx.globalCompositeOperation = 'copy';
+ ctx.shadowOffsetX = -7;
+ ctx.shadowOffsetY = 7;
+ ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
+ ctx.shadowBlur = 3;
+
+ ctx.beginLayer();
+
+ // Enable compositing in the layer to validate that draw calls in the layer
+ // won't individually composite with the background.
+ ctx.globalCompositeOperation = 'screen';
+
+ 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();
+ </script>
+</span>
+
+<span>
+ <div>globalAlpha</div>
+ <canvas id="canvas1" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas1");
+ const ctx = canvas.getContext('2d');
+
+ ctx.translate(50, 40);
+ ctx.rotate(Math.PI);
+ ctx.translate(-45, -45);
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ ctx.globalAlpha = 0.75;
+ ctx.globalCompositeOperation = 'copy';
+ ctx.shadowOffsetX = -7;
+ ctx.shadowOffsetY = 7;
+ ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
+ ctx.shadowBlur = 3;
+
+ ctx.beginLayer();
+
+ // Enable compositing in the layer to validate that draw calls in the layer
+ // won't individually composite with the background.
+ ctx.globalCompositeOperation = 'screen';
+
+ 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();
+ </script>
+</span>
+
+</div>
diff --git a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.alpha-expected.html b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.alpha-expected.html
deleted file mode 100644
index f304700feb..0000000000
--- a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.alpha-expected.html
+++ /dev/null
@@ -1,50 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<title>Canvas test: 2d.layer.global-states.filter.alpha</title>
-<h1>2d.layer.global-states.filter.alpha</h1>
-<p class="desc">Checks that layers with filters correctly use global render states.</p>
-<canvas id="canvas" width="200" height="200">
- <p class="fallback">FAIL (fallback content)</p>
-</canvas>
-<script>
- const canvas = document.getElementById("canvas");
- const ctx = canvas.getContext('2d');
-
- const svg = `
- <svg xmlns="http://www.w3.org/2000/svg"
- width="200" height="200"
- 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" />
- <feComponentTransfer>
- <feFuncA type="table" tableValues="0 0.7"></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)"/>
- </g>
- </svg>`;
-
- const img = new Image();
- img.width = 200;
- img.height = 200;
- img.onload = () => {
- ctx.fillStyle = 'rgba(0, 0, 255, 1)';
-
- var circle = new Path2D();
- circle.arc(90, 90, 45, 0, 2 * Math.PI);
- ctx.fill(circle);
-
- ctx.globalAlpha = 0.6;
-
- ctx.drawImage(img, 0, 0);
- };
- img.src = 'data:image/svg+xml;base64,' + btoa(svg);
-</script>
diff --git a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.alpha.blending-expected.html b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.alpha.blending-expected.html
deleted file mode 100644
index 7c91ce4229..0000000000
--- a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.alpha.blending-expected.html
+++ /dev/null
@@ -1,51 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<title>Canvas test: 2d.layer.global-states.filter.alpha.blending</title>
-<h1>2d.layer.global-states.filter.alpha.blending</h1>
-<p class="desc">Checks that layers with filters correctly use global render states.</p>
-<canvas id="canvas" width="200" height="200">
- <p class="fallback">FAIL (fallback content)</p>
-</canvas>
-<script>
- const canvas = document.getElementById("canvas");
- const ctx = canvas.getContext('2d');
-
- const svg = `
- <svg xmlns="http://www.w3.org/2000/svg"
- width="200" height="200"
- 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" />
- <feComponentTransfer>
- <feFuncA type="table" tableValues="0 0.7"></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)"/>
- </g>
- </svg>`;
-
- const img = new Image();
- img.width = 200;
- img.height = 200;
- img.onload = () => {
- ctx.fillStyle = 'rgba(0, 0, 255, 1)';
-
- var circle = new Path2D();
- circle.arc(90, 90, 45, 0, 2 * Math.PI);
- ctx.fill(circle);
-
- ctx.globalAlpha = 0.6;
- ctx.globalCompositeOperation = 'multiply';
-
- ctx.drawImage(img, 0, 0);
- };
- img.src = 'data:image/svg+xml;base64,' + btoa(svg);
-</script>
diff --git a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.alpha.blending.html b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.alpha.blending.html
deleted file mode 100644
index 98ea67e9e9..0000000000
--- a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.alpha.blending.html
+++ /dev/null
@@ -1,39 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<link rel="match" href="2d.layer.global-states.filter.alpha.blending-expected.html">
-<meta name=fuzzy content="maxDifference=0-1; totalPixels=0-2453">
-<title>Canvas test: 2d.layer.global-states.filter.alpha.blending</title>
-<h1>2d.layer.global-states.filter.alpha.blending</h1>
-<p class="desc">Checks that layers with filters correctly use global render states.</p>
-<canvas id="canvas" width="200" height="200">
- <p class="fallback">FAIL (fallback content)</p>
-</canvas>
-<script>
- const canvas = document.getElementById("canvas");
- const ctx = canvas.getContext('2d');
-
- ctx.fillStyle = 'rgba(0, 0, 255, 1)';
-
- var circle = new Path2D();
- circle.arc(90, 90, 45, 0, 2 * Math.PI);
- ctx.fill(circle);
-
- ctx.globalAlpha = 0.6;
- ctx.globalCompositeOperation = 'multiply';
-
- 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: 'componentTransfer',
- funcA: {type: "table", tableValues: [0, 0.7]}},
- {name: 'dropShadow', dx: 5, dy: 5, floodColor: '#81e'}]});
-
- 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.endLayer();
-</script>
diff --git a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.alpha.blending.shadow-expected.html b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.alpha.blending.shadow-expected.html
deleted file mode 100644
index 62942ffeae..0000000000
--- a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.alpha.blending.shadow-expected.html
+++ /dev/null
@@ -1,55 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<title>Canvas test: 2d.layer.global-states.filter.alpha.blending.shadow</title>
-<h1>2d.layer.global-states.filter.alpha.blending.shadow</h1>
-<p class="desc">Checks that layers with filters correctly use global render states.</p>
-<canvas id="canvas" width="200" height="200">
- <p class="fallback">FAIL (fallback content)</p>
-</canvas>
-<script>
- const canvas = document.getElementById("canvas");
- const ctx = canvas.getContext('2d');
-
- const svg = `
- <svg xmlns="http://www.w3.org/2000/svg"
- width="200" height="200"
- 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" />
- <feComponentTransfer>
- <feFuncA type="table" tableValues="0 0.7"></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)"/>
- </g>
- </svg>`;
-
- const img = new Image();
- img.width = 200;
- img.height = 200;
- img.onload = () => {
- ctx.fillStyle = 'rgba(0, 0, 255, 1)';
-
- var circle = new Path2D();
- circle.arc(90, 90, 45, 0, 2 * Math.PI);
- ctx.fill(circle);
-
- ctx.globalAlpha = 0.6;
- ctx.globalCompositeOperation = 'multiply';
- ctx.shadowOffsetX = -10;
- ctx.shadowOffsetY = 10;
- ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
- ctx.shadowBlur = 3;
-
- ctx.drawImage(img, 0, 0);
- };
- img.src = 'data:image/svg+xml;base64,' + btoa(svg);
-</script>
diff --git a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.alpha.blending.shadow.html b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.alpha.blending.shadow.html
deleted file mode 100644
index ccadfb624b..0000000000
--- a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.alpha.blending.shadow.html
+++ /dev/null
@@ -1,42 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<link rel="match" href="2d.layer.global-states.filter.alpha.blending.shadow-expected.html">
-<title>Canvas test: 2d.layer.global-states.filter.alpha.blending.shadow</title>
-<h1>2d.layer.global-states.filter.alpha.blending.shadow</h1>
-<p class="desc">Checks that layers with filters correctly use global render states.</p>
-<canvas id="canvas" width="200" height="200">
- <p class="fallback">FAIL (fallback content)</p>
-</canvas>
-<script>
- const canvas = document.getElementById("canvas");
- const ctx = canvas.getContext('2d');
-
- ctx.fillStyle = 'rgba(0, 0, 255, 1)';
-
- var circle = new Path2D();
- circle.arc(90, 90, 45, 0, 2 * Math.PI);
- ctx.fill(circle);
-
- ctx.globalAlpha = 0.6;
- ctx.globalCompositeOperation = 'multiply';
- ctx.shadowOffsetX = -10;
- ctx.shadowOffsetY = 10;
- ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
- ctx.shadowBlur = 3;
-
- 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: 'componentTransfer',
- funcA: {type: "table", tableValues: [0, 0.7]}},
- {name: 'dropShadow', dx: 5, dy: 5, floodColor: '#81e'}]});
-
- 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.endLayer();
-</script>
diff --git a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.alpha.composite-expected.html b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.alpha.composite-expected.html
deleted file mode 100644
index 8e0d98648e..0000000000
--- a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.alpha.composite-expected.html
+++ /dev/null
@@ -1,51 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<title>Canvas test: 2d.layer.global-states.filter.alpha.composite</title>
-<h1>2d.layer.global-states.filter.alpha.composite</h1>
-<p class="desc">Checks that layers with filters correctly use global render states.</p>
-<canvas id="canvas" width="200" height="200">
- <p class="fallback">FAIL (fallback content)</p>
-</canvas>
-<script>
- const canvas = document.getElementById("canvas");
- const ctx = canvas.getContext('2d');
-
- const svg = `
- <svg xmlns="http://www.w3.org/2000/svg"
- width="200" height="200"
- 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" />
- <feComponentTransfer>
- <feFuncA type="table" tableValues="0 0.7"></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)"/>
- </g>
- </svg>`;
-
- const img = new Image();
- img.width = 200;
- img.height = 200;
- img.onload = () => {
- ctx.fillStyle = 'rgba(0, 0, 255, 1)';
-
- var circle = new Path2D();
- circle.arc(90, 90, 45, 0, 2 * Math.PI);
- ctx.fill(circle);
-
- ctx.globalAlpha = 0.6;
- ctx.globalCompositeOperation = 'source-in';
-
- ctx.drawImage(img, 0, 0);
- };
- img.src = 'data:image/svg+xml;base64,' + btoa(svg);
-</script>
diff --git a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.alpha.composite.html b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.alpha.composite.html
deleted file mode 100644
index 29041d4933..0000000000
--- a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.alpha.composite.html
+++ /dev/null
@@ -1,39 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<link rel="match" href="2d.layer.global-states.filter.alpha.composite-expected.html">
-<meta name=fuzzy content="maxDifference=0-1; totalPixels=0-5204">
-<title>Canvas test: 2d.layer.global-states.filter.alpha.composite</title>
-<h1>2d.layer.global-states.filter.alpha.composite</h1>
-<p class="desc">Checks that layers with filters correctly use global render states.</p>
-<canvas id="canvas" width="200" height="200">
- <p class="fallback">FAIL (fallback content)</p>
-</canvas>
-<script>
- const canvas = document.getElementById("canvas");
- const ctx = canvas.getContext('2d');
-
- ctx.fillStyle = 'rgba(0, 0, 255, 1)';
-
- var circle = new Path2D();
- circle.arc(90, 90, 45, 0, 2 * Math.PI);
- ctx.fill(circle);
-
- ctx.globalAlpha = 0.6;
- ctx.globalCompositeOperation = 'source-in';
-
- 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: 'componentTransfer',
- funcA: {type: "table", tableValues: [0, 0.7]}},
- {name: 'dropShadow', dx: 5, dy: 5, floodColor: '#81e'}]});
-
- 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.endLayer();
-</script>
diff --git a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.alpha.composite.shadow-expected.html b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.alpha.composite.shadow-expected.html
deleted file mode 100644
index a649972546..0000000000
--- a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.alpha.composite.shadow-expected.html
+++ /dev/null
@@ -1,55 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<title>Canvas test: 2d.layer.global-states.filter.alpha.composite.shadow</title>
-<h1>2d.layer.global-states.filter.alpha.composite.shadow</h1>
-<p class="desc">Checks that layers with filters correctly use global render states.</p>
-<canvas id="canvas" width="200" height="200">
- <p class="fallback">FAIL (fallback content)</p>
-</canvas>
-<script>
- const canvas = document.getElementById("canvas");
- const ctx = canvas.getContext('2d');
-
- const svg = `
- <svg xmlns="http://www.w3.org/2000/svg"
- width="200" height="200"
- 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" />
- <feComponentTransfer>
- <feFuncA type="table" tableValues="0 0.7"></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)"/>
- </g>
- </svg>`;
-
- const img = new Image();
- img.width = 200;
- img.height = 200;
- img.onload = () => {
- ctx.fillStyle = 'rgba(0, 0, 255, 1)';
-
- var circle = new Path2D();
- circle.arc(90, 90, 45, 0, 2 * Math.PI);
- ctx.fill(circle);
-
- 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;
-
- ctx.drawImage(img, 0, 0);
- };
- img.src = 'data:image/svg+xml;base64,' + btoa(svg);
-</script>
diff --git a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.alpha.composite.shadow.html b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.alpha.composite.shadow.html
deleted file mode 100644
index b2907f02aa..0000000000
--- a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.alpha.composite.shadow.html
+++ /dev/null
@@ -1,42 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<link rel="match" href="2d.layer.global-states.filter.alpha.composite.shadow-expected.html">
-<title>Canvas test: 2d.layer.global-states.filter.alpha.composite.shadow</title>
-<h1>2d.layer.global-states.filter.alpha.composite.shadow</h1>
-<p class="desc">Checks that layers with filters correctly use global render states.</p>
-<canvas id="canvas" width="200" height="200">
- <p class="fallback">FAIL (fallback content)</p>
-</canvas>
-<script>
- const canvas = document.getElementById("canvas");
- const ctx = canvas.getContext('2d');
-
- ctx.fillStyle = 'rgba(0, 0, 255, 1)';
-
- var circle = new Path2D();
- circle.arc(90, 90, 45, 0, 2 * Math.PI);
- ctx.fill(circle);
-
- 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;
-
- 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: 'componentTransfer',
- funcA: {type: "table", tableValues: [0, 0.7]}},
- {name: 'dropShadow', dx: 5, dy: 5, floodColor: '#81e'}]});
-
- 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.endLayer();
-</script>
diff --git a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.alpha.html b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.alpha.html
deleted file mode 100644
index 85718cffba..0000000000
--- a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.alpha.html
+++ /dev/null
@@ -1,38 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<link rel="match" href="2d.layer.global-states.filter.alpha-expected.html">
-<meta name=fuzzy content="maxDifference=0-2; totalPixels=0-6766">
-<title>Canvas test: 2d.layer.global-states.filter.alpha</title>
-<h1>2d.layer.global-states.filter.alpha</h1>
-<p class="desc">Checks that layers with filters correctly use global render states.</p>
-<canvas id="canvas" width="200" height="200">
- <p class="fallback">FAIL (fallback content)</p>
-</canvas>
-<script>
- const canvas = document.getElementById("canvas");
- const ctx = canvas.getContext('2d');
-
- ctx.fillStyle = 'rgba(0, 0, 255, 1)';
-
- var circle = new Path2D();
- circle.arc(90, 90, 45, 0, 2 * Math.PI);
- ctx.fill(circle);
-
- ctx.globalAlpha = 0.6;
-
- 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: 'componentTransfer',
- funcA: {type: "table", tableValues: [0, 0.7]}},
- {name: 'dropShadow', dx: 5, dy: 5, floodColor: '#81e'}]});
-
- 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.endLayer();
-</script>
diff --git a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.alpha.shadow-expected.html b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.alpha.shadow-expected.html
deleted file mode 100644
index 169baee29b..0000000000
--- a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.alpha.shadow-expected.html
+++ /dev/null
@@ -1,54 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<title>Canvas test: 2d.layer.global-states.filter.alpha.shadow</title>
-<h1>2d.layer.global-states.filter.alpha.shadow</h1>
-<p class="desc">Checks that layers with filters correctly use global render states.</p>
-<canvas id="canvas" width="200" height="200">
- <p class="fallback">FAIL (fallback content)</p>
-</canvas>
-<script>
- const canvas = document.getElementById("canvas");
- const ctx = canvas.getContext('2d');
-
- const svg = `
- <svg xmlns="http://www.w3.org/2000/svg"
- width="200" height="200"
- 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" />
- <feComponentTransfer>
- <feFuncA type="table" tableValues="0 0.7"></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)"/>
- </g>
- </svg>`;
-
- const img = new Image();
- img.width = 200;
- img.height = 200;
- img.onload = () => {
- ctx.fillStyle = 'rgba(0, 0, 255, 1)';
-
- var circle = new Path2D();
- circle.arc(90, 90, 45, 0, 2 * Math.PI);
- ctx.fill(circle);
-
- ctx.globalAlpha = 0.5;
- ctx.shadowOffsetX = -10;
- ctx.shadowOffsetY = 10;
- ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
- ctx.shadowBlur = 3;
-
- ctx.drawImage(img, 0, 0);
- };
- img.src = 'data:image/svg+xml;base64,' + btoa(svg);
-</script>
diff --git a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.alpha.shadow.html b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.alpha.shadow.html
deleted file mode 100644
index aaeb167ccf..0000000000
--- a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.alpha.shadow.html
+++ /dev/null
@@ -1,42 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<link rel="match" href="2d.layer.global-states.filter.alpha.shadow-expected.html">
-<meta name=fuzzy content="maxDifference=0-2; totalPixels=0-6311">
-<title>Canvas test: 2d.layer.global-states.filter.alpha.shadow</title>
-<h1>2d.layer.global-states.filter.alpha.shadow</h1>
-<p class="desc">Checks that layers with filters correctly use global render states.</p>
-<canvas id="canvas" width="200" height="200">
- <p class="fallback">FAIL (fallback content)</p>
-</canvas>
-<script>
- const canvas = document.getElementById("canvas");
- const ctx = canvas.getContext('2d');
-
- ctx.fillStyle = 'rgba(0, 0, 255, 1)';
-
- var circle = new Path2D();
- circle.arc(90, 90, 45, 0, 2 * Math.PI);
- ctx.fill(circle);
-
- ctx.globalAlpha = 0.5;
- ctx.shadowOffsetX = -10;
- ctx.shadowOffsetY = 10;
- ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
- ctx.shadowBlur = 3;
-
- 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: 'componentTransfer',
- funcA: {type: "table", tableValues: [0, 0.7]}},
- {name: 'dropShadow', dx: 5, dy: 5, floodColor: '#81e'}]});
-
- 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.endLayer();
-</script>
diff --git a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.blending-expected.html b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.blending-expected.html
deleted file mode 100644
index f81dcf72dc..0000000000
--- a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.blending-expected.html
+++ /dev/null
@@ -1,50 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<title>Canvas test: 2d.layer.global-states.filter.blending</title>
-<h1>2d.layer.global-states.filter.blending</h1>
-<p class="desc">Checks that layers with filters correctly use global render states.</p>
-<canvas id="canvas" width="200" height="200">
- <p class="fallback">FAIL (fallback content)</p>
-</canvas>
-<script>
- const canvas = document.getElementById("canvas");
- const ctx = canvas.getContext('2d');
-
- const svg = `
- <svg xmlns="http://www.w3.org/2000/svg"
- width="200" height="200"
- 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" />
- <feComponentTransfer>
- <feFuncA type="table" tableValues="0 0.7"></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)"/>
- </g>
- </svg>`;
-
- const img = new Image();
- img.width = 200;
- img.height = 200;
- img.onload = () => {
- ctx.fillStyle = 'rgba(0, 0, 255, 1)';
-
- var circle = new Path2D();
- circle.arc(90, 90, 45, 0, 2 * Math.PI);
- ctx.fill(circle);
-
- ctx.globalCompositeOperation = 'multiply';
-
- ctx.drawImage(img, 0, 0);
- };
- img.src = 'data:image/svg+xml;base64,' + btoa(svg);
-</script>
diff --git a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.blending.html b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.blending.html
deleted file mode 100644
index 31628812c2..0000000000
--- a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.blending.html
+++ /dev/null
@@ -1,37 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<link rel="match" href="2d.layer.global-states.filter.blending-expected.html">
-<title>Canvas test: 2d.layer.global-states.filter.blending</title>
-<h1>2d.layer.global-states.filter.blending</h1>
-<p class="desc">Checks that layers with filters correctly use global render states.</p>
-<canvas id="canvas" width="200" height="200">
- <p class="fallback">FAIL (fallback content)</p>
-</canvas>
-<script>
- const canvas = document.getElementById("canvas");
- const ctx = canvas.getContext('2d');
-
- ctx.fillStyle = 'rgba(0, 0, 255, 1)';
-
- var circle = new Path2D();
- circle.arc(90, 90, 45, 0, 2 * Math.PI);
- ctx.fill(circle);
-
- ctx.globalCompositeOperation = 'multiply';
-
- 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: 'componentTransfer',
- funcA: {type: "table", tableValues: [0, 0.7]}},
- {name: 'dropShadow', dx: 5, dy: 5, floodColor: '#81e'}]});
-
- 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.endLayer();
-</script>
diff --git a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.blending.no-shadow.no-transform-expected.html b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.blending.no-shadow.no-transform-expected.html
new file mode 100644
index 0000000000..482ab25a85
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.blending.no-shadow.no-transform-expected.html
@@ -0,0 +1,98 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<title>Canvas test: 2d.layer.global-states.filter.blending.no-shadow.no-transform</title>
+<h1 style="font-size: 20px;">2d.layer.global-states.filter.blending.no-shadow.no-transform</h1>
+<p class="desc">Checks that layers with filters correctly use global render states.</p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(2, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>no-globalAlpha</div>
+ <canvas id="canvas0" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas0");
+ const ctx = canvas.getContext('2d');
+
+ const svg = `
+ <svg xmlns="http://www.w3.org/2000/svg"
+ width="90" height="90"
+ color-interpolation-filters="sRGB">
+ <filter id="filter" x="-100%" y="-100%" width="300%" height="300%">
+ <feDropShadow dx="5" dy="5" stdDeviation="0" flood-color="#00f" />
+ <feComponentTransfer>
+ <feFuncA type="table" tableValues="0 0.8"></feFuncA>
+ </feComponentTransfer>
+ </filter>
+ <g filter="url(#filter)">
+ <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>`;
+
+ const img = new Image();
+ img.width = 90;
+ img.height = 90;
+ img.onload = () => {
+ // No transform.
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ // No globalAlpha.
+ ctx.globalCompositeOperation = 'multiply';
+ // No shadow.
+
+ ctx.drawImage(img, 0, 0);
+ };
+ img.src = 'data:image/svg+xml;base64,' + btoa(svg);
+ </script>
+</span>
+
+<span>
+ <div>globalAlpha</div>
+ <canvas id="canvas1" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas1");
+ const ctx = canvas.getContext('2d');
+
+ const svg = `
+ <svg xmlns="http://www.w3.org/2000/svg"
+ width="90" height="90"
+ color-interpolation-filters="sRGB">
+ <filter id="filter" x="-100%" y="-100%" width="300%" height="300%">
+ <feDropShadow dx="5" dy="5" stdDeviation="0" flood-color="#00f" />
+ <feComponentTransfer>
+ <feFuncA type="table" tableValues="0 0.8"></feFuncA>
+ </feComponentTransfer>
+ </filter>
+ <g filter="url(#filter)">
+ <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>`;
+
+ const img = new Image();
+ img.width = 90;
+ img.height = 90;
+ img.onload = () => {
+ // No transform.
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ ctx.globalAlpha = 0.75;
+ ctx.globalCompositeOperation = 'multiply';
+ // No shadow.
+
+ ctx.drawImage(img, 0, 0);
+ };
+ img.src = 'data:image/svg+xml;base64,' + btoa(svg);
+ </script>
+</span>
+
+</div>
diff --git a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.blending.no-shadow.no-transform.html b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.blending.no-shadow.no-transform.html
new file mode 100644
index 0000000000..188d5ea98b
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.blending.no-shadow.no-transform.html
@@ -0,0 +1,77 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<link rel="match" href="2d.layer.global-states.filter.blending.no-shadow.no-transform-expected.html">
+<title>Canvas test: 2d.layer.global-states.filter.blending.no-shadow.no-transform</title>
+<h1 style="font-size: 20px;">2d.layer.global-states.filter.blending.no-shadow.no-transform</h1>
+<p class="desc">Checks that layers with filters correctly use global render states.</p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(2, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>no-globalAlpha</div>
+ <canvas id="canvas0" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas0");
+ const ctx = canvas.getContext('2d');
+
+ // No transform.
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ // No globalAlpha.
+ ctx.globalCompositeOperation = 'multiply';
+ // No shadow.
+
+ ctx.beginLayer({filter: [
+ {name: 'dropShadow',
+ dx: 5, dy: 5, stdDeviation: 0, floodColor: '#00f'},
+ {name: 'componentTransfer',
+ funcA: {type: "table", tableValues: [0, 0.8]}}]});
+
+ 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();
+ </script>
+</span>
+
+<span>
+ <div>globalAlpha</div>
+ <canvas id="canvas1" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas1");
+ const ctx = canvas.getContext('2d');
+
+ // No transform.
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ ctx.globalAlpha = 0.75;
+ ctx.globalCompositeOperation = 'multiply';
+ // No shadow.
+
+ ctx.beginLayer({filter: [
+ {name: 'dropShadow',
+ dx: 5, dy: 5, stdDeviation: 0, floodColor: '#00f'},
+ {name: 'componentTransfer',
+ funcA: {type: "table", tableValues: [0, 0.8]}}]});
+
+ 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();
+ </script>
+</span>
+
+</div>
diff --git a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.blending.no-shadow.rotation-expected.html b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.blending.no-shadow.rotation-expected.html
new file mode 100644
index 0000000000..3af6b863ed
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.blending.no-shadow.rotation-expected.html
@@ -0,0 +1,102 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<title>Canvas test: 2d.layer.global-states.filter.blending.no-shadow.rotation</title>
+<h1 style="font-size: 20px;">2d.layer.global-states.filter.blending.no-shadow.rotation</h1>
+<p class="desc">Checks that layers with filters correctly use global render states.</p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(2, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>no-globalAlpha</div>
+ <canvas id="canvas0" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas0");
+ const ctx = canvas.getContext('2d');
+
+ const svg = `
+ <svg xmlns="http://www.w3.org/2000/svg"
+ width="90" height="90"
+ color-interpolation-filters="sRGB">
+ <filter id="filter" x="-100%" y="-100%" width="300%" height="300%">
+ <feDropShadow dx="5" dy="5" stdDeviation="0" flood-color="#00f" />
+ <feComponentTransfer>
+ <feFuncA type="table" tableValues="0 0.8"></feFuncA>
+ </feComponentTransfer>
+ </filter>
+ <g filter="url(#filter)">
+ <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>`;
+
+ const img = new Image();
+ img.width = 90;
+ img.height = 90;
+ img.onload = () => {
+ ctx.translate(50, 40);
+ ctx.rotate(Math.PI);
+ ctx.translate(-45, -45);
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ // No globalAlpha.
+ ctx.globalCompositeOperation = 'multiply';
+ // No shadow.
+
+ ctx.drawImage(img, 0, 0);
+ };
+ img.src = 'data:image/svg+xml;base64,' + btoa(svg);
+ </script>
+</span>
+
+<span>
+ <div>globalAlpha</div>
+ <canvas id="canvas1" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas1");
+ const ctx = canvas.getContext('2d');
+
+ const svg = `
+ <svg xmlns="http://www.w3.org/2000/svg"
+ width="90" height="90"
+ color-interpolation-filters="sRGB">
+ <filter id="filter" x="-100%" y="-100%" width="300%" height="300%">
+ <feDropShadow dx="5" dy="5" stdDeviation="0" flood-color="#00f" />
+ <feComponentTransfer>
+ <feFuncA type="table" tableValues="0 0.8"></feFuncA>
+ </feComponentTransfer>
+ </filter>
+ <g filter="url(#filter)">
+ <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>`;
+
+ const img = new Image();
+ img.width = 90;
+ img.height = 90;
+ img.onload = () => {
+ ctx.translate(50, 40);
+ ctx.rotate(Math.PI);
+ ctx.translate(-45, -45);
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ ctx.globalAlpha = 0.75;
+ ctx.globalCompositeOperation = 'multiply';
+ // No shadow.
+
+ ctx.drawImage(img, 0, 0);
+ };
+ img.src = 'data:image/svg+xml;base64,' + btoa(svg);
+ </script>
+</span>
+
+</div>
diff --git a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.blending.no-shadow.rotation.html b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.blending.no-shadow.rotation.html
new file mode 100644
index 0000000000..849a0c997e
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.blending.no-shadow.rotation.html
@@ -0,0 +1,81 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<link rel="match" href="2d.layer.global-states.filter.blending.no-shadow.rotation-expected.html">
+<title>Canvas test: 2d.layer.global-states.filter.blending.no-shadow.rotation</title>
+<h1 style="font-size: 20px;">2d.layer.global-states.filter.blending.no-shadow.rotation</h1>
+<p class="desc">Checks that layers with filters correctly use global render states.</p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(2, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>no-globalAlpha</div>
+ <canvas id="canvas0" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas0");
+ const ctx = canvas.getContext('2d');
+
+ ctx.translate(50, 40);
+ ctx.rotate(Math.PI);
+ ctx.translate(-45, -45);
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ // No globalAlpha.
+ ctx.globalCompositeOperation = 'multiply';
+ // No shadow.
+
+ ctx.beginLayer({filter: [
+ {name: 'dropShadow',
+ dx: 5, dy: 5, stdDeviation: 0, floodColor: '#00f'},
+ {name: 'componentTransfer',
+ funcA: {type: "table", tableValues: [0, 0.8]}}]});
+
+ 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();
+ </script>
+</span>
+
+<span>
+ <div>globalAlpha</div>
+ <canvas id="canvas1" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas1");
+ const ctx = canvas.getContext('2d');
+
+ ctx.translate(50, 40);
+ ctx.rotate(Math.PI);
+ ctx.translate(-45, -45);
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ ctx.globalAlpha = 0.75;
+ ctx.globalCompositeOperation = 'multiply';
+ // No shadow.
+
+ ctx.beginLayer({filter: [
+ {name: 'dropShadow',
+ dx: 5, dy: 5, stdDeviation: 0, floodColor: '#00f'},
+ {name: 'componentTransfer',
+ funcA: {type: "table", tableValues: [0, 0.8]}}]});
+
+ 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();
+ </script>
+</span>
+
+</div>
diff --git a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.blending.shadow-expected.html b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.blending.shadow-expected.html
deleted file mode 100644
index 91f3725f8e..0000000000
--- a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.blending.shadow-expected.html
+++ /dev/null
@@ -1,54 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<title>Canvas test: 2d.layer.global-states.filter.blending.shadow</title>
-<h1>2d.layer.global-states.filter.blending.shadow</h1>
-<p class="desc">Checks that layers with filters correctly use global render states.</p>
-<canvas id="canvas" width="200" height="200">
- <p class="fallback">FAIL (fallback content)</p>
-</canvas>
-<script>
- const canvas = document.getElementById("canvas");
- const ctx = canvas.getContext('2d');
-
- const svg = `
- <svg xmlns="http://www.w3.org/2000/svg"
- width="200" height="200"
- 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" />
- <feComponentTransfer>
- <feFuncA type="table" tableValues="0 0.7"></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)"/>
- </g>
- </svg>`;
-
- const img = new Image();
- img.width = 200;
- img.height = 200;
- img.onload = () => {
- ctx.fillStyle = 'rgba(0, 0, 255, 1)';
-
- var circle = new Path2D();
- circle.arc(90, 90, 45, 0, 2 * Math.PI);
- ctx.fill(circle);
-
- ctx.globalCompositeOperation = 'multiply';
- ctx.shadowOffsetX = -10;
- ctx.shadowOffsetY = 10;
- ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
- ctx.shadowBlur = 3;
-
- ctx.drawImage(img, 0, 0);
- };
- img.src = 'data:image/svg+xml;base64,' + btoa(svg);
-</script>
diff --git a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.blending.shadow.html b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.blending.shadow.html
deleted file mode 100644
index e54cf06d0d..0000000000
--- a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.blending.shadow.html
+++ /dev/null
@@ -1,41 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<link rel="match" href="2d.layer.global-states.filter.blending.shadow-expected.html">
-<title>Canvas test: 2d.layer.global-states.filter.blending.shadow</title>
-<h1>2d.layer.global-states.filter.blending.shadow</h1>
-<p class="desc">Checks that layers with filters correctly use global render states.</p>
-<canvas id="canvas" width="200" height="200">
- <p class="fallback">FAIL (fallback content)</p>
-</canvas>
-<script>
- const canvas = document.getElementById("canvas");
- const ctx = canvas.getContext('2d');
-
- ctx.fillStyle = 'rgba(0, 0, 255, 1)';
-
- var circle = new Path2D();
- circle.arc(90, 90, 45, 0, 2 * Math.PI);
- ctx.fill(circle);
-
- ctx.globalCompositeOperation = 'multiply';
- ctx.shadowOffsetX = -10;
- ctx.shadowOffsetY = 10;
- ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
- ctx.shadowBlur = 3;
-
- 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: 'componentTransfer',
- funcA: {type: "table", tableValues: [0, 0.7]}},
- {name: 'dropShadow', dx: 5, dy: 5, floodColor: '#81e'}]});
-
- 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.endLayer();
-</script>
diff --git a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.blending.shadow.no-transform-expected.html b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.blending.shadow.no-transform-expected.html
new file mode 100644
index 0000000000..d530ef9d19
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.blending.shadow.no-transform-expected.html
@@ -0,0 +1,104 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<title>Canvas test: 2d.layer.global-states.filter.blending.shadow.no-transform</title>
+<h1 style="font-size: 20px;">2d.layer.global-states.filter.blending.shadow.no-transform</h1>
+<p class="desc">Checks that layers with filters correctly use global render states.</p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(2, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>no-globalAlpha</div>
+ <canvas id="canvas0" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas0");
+ const ctx = canvas.getContext('2d');
+
+ const svg = `
+ <svg xmlns="http://www.w3.org/2000/svg"
+ width="90" height="90"
+ color-interpolation-filters="sRGB">
+ <filter id="filter" x="-100%" y="-100%" width="300%" height="300%">
+ <feDropShadow dx="5" dy="5" stdDeviation="0" flood-color="#00f" />
+ <feComponentTransfer>
+ <feFuncA type="table" tableValues="0 0.8"></feFuncA>
+ </feComponentTransfer>
+ </filter>
+ <g filter="url(#filter)">
+ <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>`;
+
+ const img = new Image();
+ img.width = 90;
+ img.height = 90;
+ img.onload = () => {
+ // No transform.
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ // No globalAlpha.
+ ctx.globalCompositeOperation = 'multiply';
+ ctx.shadowOffsetX = -7;
+ ctx.shadowOffsetY = 7;
+ ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
+ ctx.shadowBlur = 3;
+
+ ctx.drawImage(img, 0, 0);
+ };
+ img.src = 'data:image/svg+xml;base64,' + btoa(svg);
+ </script>
+</span>
+
+<span>
+ <div>globalAlpha</div>
+ <canvas id="canvas1" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas1");
+ const ctx = canvas.getContext('2d');
+
+ const svg = `
+ <svg xmlns="http://www.w3.org/2000/svg"
+ width="90" height="90"
+ color-interpolation-filters="sRGB">
+ <filter id="filter" x="-100%" y="-100%" width="300%" height="300%">
+ <feDropShadow dx="5" dy="5" stdDeviation="0" flood-color="#00f" />
+ <feComponentTransfer>
+ <feFuncA type="table" tableValues="0 0.8"></feFuncA>
+ </feComponentTransfer>
+ </filter>
+ <g filter="url(#filter)">
+ <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>`;
+
+ const img = new Image();
+ img.width = 90;
+ img.height = 90;
+ img.onload = () => {
+ // No transform.
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ ctx.globalAlpha = 0.75;
+ ctx.globalCompositeOperation = 'multiply';
+ ctx.shadowOffsetX = -7;
+ ctx.shadowOffsetY = 7;
+ ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
+ ctx.shadowBlur = 3;
+
+ ctx.drawImage(img, 0, 0);
+ };
+ img.src = 'data:image/svg+xml;base64,' + btoa(svg);
+ </script>
+</span>
+
+</div>
diff --git a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.blending.shadow.no-transform.html b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.blending.shadow.no-transform.html
new file mode 100644
index 0000000000..34ded8fef5
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.blending.shadow.no-transform.html
@@ -0,0 +1,83 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<link rel="match" href="2d.layer.global-states.filter.blending.shadow.no-transform-expected.html">
+<title>Canvas test: 2d.layer.global-states.filter.blending.shadow.no-transform</title>
+<h1 style="font-size: 20px;">2d.layer.global-states.filter.blending.shadow.no-transform</h1>
+<p class="desc">Checks that layers with filters correctly use global render states.</p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(2, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>no-globalAlpha</div>
+ <canvas id="canvas0" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas0");
+ const ctx = canvas.getContext('2d');
+
+ // No transform.
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ // No globalAlpha.
+ ctx.globalCompositeOperation = 'multiply';
+ ctx.shadowOffsetX = -7;
+ ctx.shadowOffsetY = 7;
+ ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
+ ctx.shadowBlur = 3;
+
+ ctx.beginLayer({filter: [
+ {name: 'dropShadow',
+ dx: 5, dy: 5, stdDeviation: 0, floodColor: '#00f'},
+ {name: 'componentTransfer',
+ funcA: {type: "table", tableValues: [0, 0.8]}}]});
+
+ 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();
+ </script>
+</span>
+
+<span>
+ <div>globalAlpha</div>
+ <canvas id="canvas1" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas1");
+ const ctx = canvas.getContext('2d');
+
+ // No transform.
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ ctx.globalAlpha = 0.75;
+ ctx.globalCompositeOperation = 'multiply';
+ ctx.shadowOffsetX = -7;
+ ctx.shadowOffsetY = 7;
+ ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
+ ctx.shadowBlur = 3;
+
+ ctx.beginLayer({filter: [
+ {name: 'dropShadow',
+ dx: 5, dy: 5, stdDeviation: 0, floodColor: '#00f'},
+ {name: 'componentTransfer',
+ funcA: {type: "table", tableValues: [0, 0.8]}}]});
+
+ 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();
+ </script>
+</span>
+
+</div>
diff --git a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.blending.shadow.rotation-expected.html b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.blending.shadow.rotation-expected.html
new file mode 100644
index 0000000000..80705c36fd
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.blending.shadow.rotation-expected.html
@@ -0,0 +1,108 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<title>Canvas test: 2d.layer.global-states.filter.blending.shadow.rotation</title>
+<h1 style="font-size: 20px;">2d.layer.global-states.filter.blending.shadow.rotation</h1>
+<p class="desc">Checks that layers with filters correctly use global render states.</p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(2, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>no-globalAlpha</div>
+ <canvas id="canvas0" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas0");
+ const ctx = canvas.getContext('2d');
+
+ const svg = `
+ <svg xmlns="http://www.w3.org/2000/svg"
+ width="90" height="90"
+ color-interpolation-filters="sRGB">
+ <filter id="filter" x="-100%" y="-100%" width="300%" height="300%">
+ <feDropShadow dx="5" dy="5" stdDeviation="0" flood-color="#00f" />
+ <feComponentTransfer>
+ <feFuncA type="table" tableValues="0 0.8"></feFuncA>
+ </feComponentTransfer>
+ </filter>
+ <g filter="url(#filter)">
+ <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>`;
+
+ const img = new Image();
+ img.width = 90;
+ img.height = 90;
+ img.onload = () => {
+ ctx.translate(50, 40);
+ ctx.rotate(Math.PI);
+ ctx.translate(-45, -45);
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ // No globalAlpha.
+ ctx.globalCompositeOperation = 'multiply';
+ ctx.shadowOffsetX = -7;
+ ctx.shadowOffsetY = 7;
+ ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
+ ctx.shadowBlur = 3;
+
+ ctx.drawImage(img, 0, 0);
+ };
+ img.src = 'data:image/svg+xml;base64,' + btoa(svg);
+ </script>
+</span>
+
+<span>
+ <div>globalAlpha</div>
+ <canvas id="canvas1" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas1");
+ const ctx = canvas.getContext('2d');
+
+ const svg = `
+ <svg xmlns="http://www.w3.org/2000/svg"
+ width="90" height="90"
+ color-interpolation-filters="sRGB">
+ <filter id="filter" x="-100%" y="-100%" width="300%" height="300%">
+ <feDropShadow dx="5" dy="5" stdDeviation="0" flood-color="#00f" />
+ <feComponentTransfer>
+ <feFuncA type="table" tableValues="0 0.8"></feFuncA>
+ </feComponentTransfer>
+ </filter>
+ <g filter="url(#filter)">
+ <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>`;
+
+ const img = new Image();
+ img.width = 90;
+ img.height = 90;
+ img.onload = () => {
+ ctx.translate(50, 40);
+ ctx.rotate(Math.PI);
+ ctx.translate(-45, -45);
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ ctx.globalAlpha = 0.75;
+ ctx.globalCompositeOperation = 'multiply';
+ ctx.shadowOffsetX = -7;
+ ctx.shadowOffsetY = 7;
+ ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
+ ctx.shadowBlur = 3;
+
+ ctx.drawImage(img, 0, 0);
+ };
+ img.src = 'data:image/svg+xml;base64,' + btoa(svg);
+ </script>
+</span>
+
+</div>
diff --git a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.blending.shadow.rotation.html b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.blending.shadow.rotation.html
new file mode 100644
index 0000000000..78407dd459
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.blending.shadow.rotation.html
@@ -0,0 +1,87 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<link rel="match" href="2d.layer.global-states.filter.blending.shadow.rotation-expected.html">
+<title>Canvas test: 2d.layer.global-states.filter.blending.shadow.rotation</title>
+<h1 style="font-size: 20px;">2d.layer.global-states.filter.blending.shadow.rotation</h1>
+<p class="desc">Checks that layers with filters correctly use global render states.</p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(2, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>no-globalAlpha</div>
+ <canvas id="canvas0" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas0");
+ const ctx = canvas.getContext('2d');
+
+ ctx.translate(50, 40);
+ ctx.rotate(Math.PI);
+ ctx.translate(-45, -45);
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ // No globalAlpha.
+ ctx.globalCompositeOperation = 'multiply';
+ ctx.shadowOffsetX = -7;
+ ctx.shadowOffsetY = 7;
+ ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
+ ctx.shadowBlur = 3;
+
+ ctx.beginLayer({filter: [
+ {name: 'dropShadow',
+ dx: 5, dy: 5, stdDeviation: 0, floodColor: '#00f'},
+ {name: 'componentTransfer',
+ funcA: {type: "table", tableValues: [0, 0.8]}}]});
+
+ 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();
+ </script>
+</span>
+
+<span>
+ <div>globalAlpha</div>
+ <canvas id="canvas1" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas1");
+ const ctx = canvas.getContext('2d');
+
+ ctx.translate(50, 40);
+ ctx.rotate(Math.PI);
+ ctx.translate(-45, -45);
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ ctx.globalAlpha = 0.75;
+ ctx.globalCompositeOperation = 'multiply';
+ ctx.shadowOffsetX = -7;
+ ctx.shadowOffsetY = 7;
+ ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
+ ctx.shadowBlur = 3;
+
+ ctx.beginLayer({filter: [
+ {name: 'dropShadow',
+ dx: 5, dy: 5, stdDeviation: 0, floodColor: '#00f'},
+ {name: 'componentTransfer',
+ funcA: {type: "table", tableValues: [0, 0.8]}}]});
+
+ 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();
+ </script>
+</span>
+
+</div>
diff --git a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.composite-expected.html b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.composite-expected.html
deleted file mode 100644
index 97e85a1593..0000000000
--- a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.composite-expected.html
+++ /dev/null
@@ -1,50 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<title>Canvas test: 2d.layer.global-states.filter.composite</title>
-<h1>2d.layer.global-states.filter.composite</h1>
-<p class="desc">Checks that layers with filters correctly use global render states.</p>
-<canvas id="canvas" width="200" height="200">
- <p class="fallback">FAIL (fallback content)</p>
-</canvas>
-<script>
- const canvas = document.getElementById("canvas");
- const ctx = canvas.getContext('2d');
-
- const svg = `
- <svg xmlns="http://www.w3.org/2000/svg"
- width="200" height="200"
- 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" />
- <feComponentTransfer>
- <feFuncA type="table" tableValues="0 0.7"></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)"/>
- </g>
- </svg>`;
-
- const img = new Image();
- img.width = 200;
- img.height = 200;
- img.onload = () => {
- ctx.fillStyle = 'rgba(0, 0, 255, 1)';
-
- var circle = new Path2D();
- circle.arc(90, 90, 45, 0, 2 * Math.PI);
- ctx.fill(circle);
-
- ctx.globalCompositeOperation = 'source-in';
-
- ctx.drawImage(img, 0, 0);
- };
- img.src = 'data:image/svg+xml;base64,' + btoa(svg);
-</script>
diff --git a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.composite.html b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.composite.html
deleted file mode 100644
index d7e365422f..0000000000
--- a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.composite.html
+++ /dev/null
@@ -1,37 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<link rel="match" href="2d.layer.global-states.filter.composite-expected.html">
-<title>Canvas test: 2d.layer.global-states.filter.composite</title>
-<h1>2d.layer.global-states.filter.composite</h1>
-<p class="desc">Checks that layers with filters correctly use global render states.</p>
-<canvas id="canvas" width="200" height="200">
- <p class="fallback">FAIL (fallback content)</p>
-</canvas>
-<script>
- const canvas = document.getElementById("canvas");
- const ctx = canvas.getContext('2d');
-
- ctx.fillStyle = 'rgba(0, 0, 255, 1)';
-
- var circle = new Path2D();
- circle.arc(90, 90, 45, 0, 2 * Math.PI);
- ctx.fill(circle);
-
- ctx.globalCompositeOperation = 'source-in';
-
- 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: 'componentTransfer',
- funcA: {type: "table", tableValues: [0, 0.7]}},
- {name: 'dropShadow', dx: 5, dy: 5, floodColor: '#81e'}]});
-
- 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.endLayer();
-</script>
diff --git a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.composite.no-shadow.no-transform-expected.html b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.composite.no-shadow.no-transform-expected.html
new file mode 100644
index 0000000000..2f513bff0a
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.composite.no-shadow.no-transform-expected.html
@@ -0,0 +1,98 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<title>Canvas test: 2d.layer.global-states.filter.composite.no-shadow.no-transform</title>
+<h1 style="font-size: 20px;">2d.layer.global-states.filter.composite.no-shadow.no-transform</h1>
+<p class="desc">Checks that layers with filters correctly use global render states.</p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(2, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>no-globalAlpha</div>
+ <canvas id="canvas0" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas0");
+ const ctx = canvas.getContext('2d');
+
+ const svg = `
+ <svg xmlns="http://www.w3.org/2000/svg"
+ width="90" height="90"
+ color-interpolation-filters="sRGB">
+ <filter id="filter" x="-100%" y="-100%" width="300%" height="300%">
+ <feDropShadow dx="5" dy="5" stdDeviation="0" flood-color="#00f" />
+ <feComponentTransfer>
+ <feFuncA type="table" tableValues="0 0.8"></feFuncA>
+ </feComponentTransfer>
+ </filter>
+ <g filter="url(#filter)">
+ <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>`;
+
+ const img = new Image();
+ img.width = 90;
+ img.height = 90;
+ img.onload = () => {
+ // No transform.
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ // No globalAlpha.
+ ctx.globalCompositeOperation = 'source-in';
+ // No shadow.
+
+ ctx.drawImage(img, 0, 0);
+ };
+ img.src = 'data:image/svg+xml;base64,' + btoa(svg);
+ </script>
+</span>
+
+<span>
+ <div>globalAlpha</div>
+ <canvas id="canvas1" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas1");
+ const ctx = canvas.getContext('2d');
+
+ const svg = `
+ <svg xmlns="http://www.w3.org/2000/svg"
+ width="90" height="90"
+ color-interpolation-filters="sRGB">
+ <filter id="filter" x="-100%" y="-100%" width="300%" height="300%">
+ <feDropShadow dx="5" dy="5" stdDeviation="0" flood-color="#00f" />
+ <feComponentTransfer>
+ <feFuncA type="table" tableValues="0 0.8"></feFuncA>
+ </feComponentTransfer>
+ </filter>
+ <g filter="url(#filter)">
+ <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>`;
+
+ const img = new Image();
+ img.width = 90;
+ img.height = 90;
+ img.onload = () => {
+ // No transform.
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ ctx.globalAlpha = 0.75;
+ ctx.globalCompositeOperation = 'source-in';
+ // No shadow.
+
+ ctx.drawImage(img, 0, 0);
+ };
+ img.src = 'data:image/svg+xml;base64,' + btoa(svg);
+ </script>
+</span>
+
+</div>
diff --git a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.composite.no-shadow.no-transform.html b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.composite.no-shadow.no-transform.html
new file mode 100644
index 0000000000..e3c36d3c0e
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.composite.no-shadow.no-transform.html
@@ -0,0 +1,77 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<link rel="match" href="2d.layer.global-states.filter.composite.no-shadow.no-transform-expected.html">
+<title>Canvas test: 2d.layer.global-states.filter.composite.no-shadow.no-transform</title>
+<h1 style="font-size: 20px;">2d.layer.global-states.filter.composite.no-shadow.no-transform</h1>
+<p class="desc">Checks that layers with filters correctly use global render states.</p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(2, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>no-globalAlpha</div>
+ <canvas id="canvas0" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas0");
+ const ctx = canvas.getContext('2d');
+
+ // No transform.
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ // No globalAlpha.
+ ctx.globalCompositeOperation = 'source-in';
+ // No shadow.
+
+ ctx.beginLayer({filter: [
+ {name: 'dropShadow',
+ dx: 5, dy: 5, stdDeviation: 0, floodColor: '#00f'},
+ {name: 'componentTransfer',
+ funcA: {type: "table", tableValues: [0, 0.8]}}]});
+
+ 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();
+ </script>
+</span>
+
+<span>
+ <div>globalAlpha</div>
+ <canvas id="canvas1" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas1");
+ const ctx = canvas.getContext('2d');
+
+ // No transform.
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ ctx.globalAlpha = 0.75;
+ ctx.globalCompositeOperation = 'source-in';
+ // No shadow.
+
+ ctx.beginLayer({filter: [
+ {name: 'dropShadow',
+ dx: 5, dy: 5, stdDeviation: 0, floodColor: '#00f'},
+ {name: 'componentTransfer',
+ funcA: {type: "table", tableValues: [0, 0.8]}}]});
+
+ 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();
+ </script>
+</span>
+
+</div>
diff --git a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.composite.no-shadow.rotation-expected.html b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.composite.no-shadow.rotation-expected.html
new file mode 100644
index 0000000000..242973300f
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.composite.no-shadow.rotation-expected.html
@@ -0,0 +1,102 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<title>Canvas test: 2d.layer.global-states.filter.composite.no-shadow.rotation</title>
+<h1 style="font-size: 20px;">2d.layer.global-states.filter.composite.no-shadow.rotation</h1>
+<p class="desc">Checks that layers with filters correctly use global render states.</p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(2, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>no-globalAlpha</div>
+ <canvas id="canvas0" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas0");
+ const ctx = canvas.getContext('2d');
+
+ const svg = `
+ <svg xmlns="http://www.w3.org/2000/svg"
+ width="90" height="90"
+ color-interpolation-filters="sRGB">
+ <filter id="filter" x="-100%" y="-100%" width="300%" height="300%">
+ <feDropShadow dx="5" dy="5" stdDeviation="0" flood-color="#00f" />
+ <feComponentTransfer>
+ <feFuncA type="table" tableValues="0 0.8"></feFuncA>
+ </feComponentTransfer>
+ </filter>
+ <g filter="url(#filter)">
+ <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>`;
+
+ const img = new Image();
+ img.width = 90;
+ img.height = 90;
+ img.onload = () => {
+ ctx.translate(50, 40);
+ ctx.rotate(Math.PI);
+ ctx.translate(-45, -45);
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ // No globalAlpha.
+ ctx.globalCompositeOperation = 'source-in';
+ // No shadow.
+
+ ctx.drawImage(img, 0, 0);
+ };
+ img.src = 'data:image/svg+xml;base64,' + btoa(svg);
+ </script>
+</span>
+
+<span>
+ <div>globalAlpha</div>
+ <canvas id="canvas1" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas1");
+ const ctx = canvas.getContext('2d');
+
+ const svg = `
+ <svg xmlns="http://www.w3.org/2000/svg"
+ width="90" height="90"
+ color-interpolation-filters="sRGB">
+ <filter id="filter" x="-100%" y="-100%" width="300%" height="300%">
+ <feDropShadow dx="5" dy="5" stdDeviation="0" flood-color="#00f" />
+ <feComponentTransfer>
+ <feFuncA type="table" tableValues="0 0.8"></feFuncA>
+ </feComponentTransfer>
+ </filter>
+ <g filter="url(#filter)">
+ <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>`;
+
+ const img = new Image();
+ img.width = 90;
+ img.height = 90;
+ img.onload = () => {
+ ctx.translate(50, 40);
+ ctx.rotate(Math.PI);
+ ctx.translate(-45, -45);
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ ctx.globalAlpha = 0.75;
+ ctx.globalCompositeOperation = 'source-in';
+ // No shadow.
+
+ ctx.drawImage(img, 0, 0);
+ };
+ img.src = 'data:image/svg+xml;base64,' + btoa(svg);
+ </script>
+</span>
+
+</div>
diff --git a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.composite.no-shadow.rotation.html b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.composite.no-shadow.rotation.html
new file mode 100644
index 0000000000..466513864e
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.composite.no-shadow.rotation.html
@@ -0,0 +1,81 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<link rel="match" href="2d.layer.global-states.filter.composite.no-shadow.rotation-expected.html">
+<title>Canvas test: 2d.layer.global-states.filter.composite.no-shadow.rotation</title>
+<h1 style="font-size: 20px;">2d.layer.global-states.filter.composite.no-shadow.rotation</h1>
+<p class="desc">Checks that layers with filters correctly use global render states.</p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(2, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>no-globalAlpha</div>
+ <canvas id="canvas0" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas0");
+ const ctx = canvas.getContext('2d');
+
+ ctx.translate(50, 40);
+ ctx.rotate(Math.PI);
+ ctx.translate(-45, -45);
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ // No globalAlpha.
+ ctx.globalCompositeOperation = 'source-in';
+ // No shadow.
+
+ ctx.beginLayer({filter: [
+ {name: 'dropShadow',
+ dx: 5, dy: 5, stdDeviation: 0, floodColor: '#00f'},
+ {name: 'componentTransfer',
+ funcA: {type: "table", tableValues: [0, 0.8]}}]});
+
+ 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();
+ </script>
+</span>
+
+<span>
+ <div>globalAlpha</div>
+ <canvas id="canvas1" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas1");
+ const ctx = canvas.getContext('2d');
+
+ ctx.translate(50, 40);
+ ctx.rotate(Math.PI);
+ ctx.translate(-45, -45);
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ ctx.globalAlpha = 0.75;
+ ctx.globalCompositeOperation = 'source-in';
+ // No shadow.
+
+ ctx.beginLayer({filter: [
+ {name: 'dropShadow',
+ dx: 5, dy: 5, stdDeviation: 0, floodColor: '#00f'},
+ {name: 'componentTransfer',
+ funcA: {type: "table", tableValues: [0, 0.8]}}]});
+
+ 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();
+ </script>
+</span>
+
+</div>
diff --git a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.composite.shadow-expected.html b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.composite.shadow-expected.html
deleted file mode 100644
index 4716bb2760..0000000000
--- a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.composite.shadow-expected.html
+++ /dev/null
@@ -1,54 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<title>Canvas test: 2d.layer.global-states.filter.composite.shadow</title>
-<h1>2d.layer.global-states.filter.composite.shadow</h1>
-<p class="desc">Checks that layers with filters correctly use global render states.</p>
-<canvas id="canvas" width="200" height="200">
- <p class="fallback">FAIL (fallback content)</p>
-</canvas>
-<script>
- const canvas = document.getElementById("canvas");
- const ctx = canvas.getContext('2d');
-
- const svg = `
- <svg xmlns="http://www.w3.org/2000/svg"
- width="200" height="200"
- 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" />
- <feComponentTransfer>
- <feFuncA type="table" tableValues="0 0.7"></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)"/>
- </g>
- </svg>`;
-
- const img = new Image();
- img.width = 200;
- img.height = 200;
- img.onload = () => {
- ctx.fillStyle = 'rgba(0, 0, 255, 1)';
-
- var circle = new Path2D();
- circle.arc(90, 90, 45, 0, 2 * Math.PI);
- ctx.fill(circle);
-
- ctx.globalCompositeOperation = 'source-in';
- ctx.shadowOffsetX = -10;
- ctx.shadowOffsetY = 10;
- ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
- ctx.shadowBlur = 3;
-
- ctx.drawImage(img, 0, 0);
- };
- img.src = 'data:image/svg+xml;base64,' + btoa(svg);
-</script>
diff --git a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.composite.shadow.html b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.composite.shadow.html
deleted file mode 100644
index e5c7698634..0000000000
--- a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.composite.shadow.html
+++ /dev/null
@@ -1,41 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<link rel="match" href="2d.layer.global-states.filter.composite.shadow-expected.html">
-<title>Canvas test: 2d.layer.global-states.filter.composite.shadow</title>
-<h1>2d.layer.global-states.filter.composite.shadow</h1>
-<p class="desc">Checks that layers with filters correctly use global render states.</p>
-<canvas id="canvas" width="200" height="200">
- <p class="fallback">FAIL (fallback content)</p>
-</canvas>
-<script>
- const canvas = document.getElementById("canvas");
- const ctx = canvas.getContext('2d');
-
- ctx.fillStyle = 'rgba(0, 0, 255, 1)';
-
- var circle = new Path2D();
- circle.arc(90, 90, 45, 0, 2 * Math.PI);
- ctx.fill(circle);
-
- ctx.globalCompositeOperation = 'source-in';
- ctx.shadowOffsetX = -10;
- ctx.shadowOffsetY = 10;
- ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
- ctx.shadowBlur = 3;
-
- 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: 'componentTransfer',
- funcA: {type: "table", tableValues: [0, 0.7]}},
- {name: 'dropShadow', dx: 5, dy: 5, floodColor: '#81e'}]});
-
- 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.endLayer();
-</script>
diff --git a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.composite.shadow.no-transform-expected.html b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.composite.shadow.no-transform-expected.html
new file mode 100644
index 0000000000..c8926e5e15
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.composite.shadow.no-transform-expected.html
@@ -0,0 +1,104 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<title>Canvas test: 2d.layer.global-states.filter.composite.shadow.no-transform</title>
+<h1 style="font-size: 20px;">2d.layer.global-states.filter.composite.shadow.no-transform</h1>
+<p class="desc">Checks that layers with filters correctly use global render states.</p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(2, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>no-globalAlpha</div>
+ <canvas id="canvas0" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas0");
+ const ctx = canvas.getContext('2d');
+
+ const svg = `
+ <svg xmlns="http://www.w3.org/2000/svg"
+ width="90" height="90"
+ color-interpolation-filters="sRGB">
+ <filter id="filter" x="-100%" y="-100%" width="300%" height="300%">
+ <feDropShadow dx="5" dy="5" stdDeviation="0" flood-color="#00f" />
+ <feComponentTransfer>
+ <feFuncA type="table" tableValues="0 0.8"></feFuncA>
+ </feComponentTransfer>
+ </filter>
+ <g filter="url(#filter)">
+ <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>`;
+
+ const img = new Image();
+ img.width = 90;
+ img.height = 90;
+ img.onload = () => {
+ // No transform.
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ // No globalAlpha.
+ ctx.globalCompositeOperation = 'source-in';
+ ctx.shadowOffsetX = -7;
+ ctx.shadowOffsetY = 7;
+ ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
+ ctx.shadowBlur = 3;
+
+ ctx.drawImage(img, 0, 0);
+ };
+ img.src = 'data:image/svg+xml;base64,' + btoa(svg);
+ </script>
+</span>
+
+<span>
+ <div>globalAlpha</div>
+ <canvas id="canvas1" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas1");
+ const ctx = canvas.getContext('2d');
+
+ const svg = `
+ <svg xmlns="http://www.w3.org/2000/svg"
+ width="90" height="90"
+ color-interpolation-filters="sRGB">
+ <filter id="filter" x="-100%" y="-100%" width="300%" height="300%">
+ <feDropShadow dx="5" dy="5" stdDeviation="0" flood-color="#00f" />
+ <feComponentTransfer>
+ <feFuncA type="table" tableValues="0 0.8"></feFuncA>
+ </feComponentTransfer>
+ </filter>
+ <g filter="url(#filter)">
+ <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>`;
+
+ const img = new Image();
+ img.width = 90;
+ img.height = 90;
+ img.onload = () => {
+ // No transform.
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ ctx.globalAlpha = 0.75;
+ ctx.globalCompositeOperation = 'source-in';
+ ctx.shadowOffsetX = -7;
+ ctx.shadowOffsetY = 7;
+ ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
+ ctx.shadowBlur = 3;
+
+ ctx.drawImage(img, 0, 0);
+ };
+ img.src = 'data:image/svg+xml;base64,' + btoa(svg);
+ </script>
+</span>
+
+</div>
diff --git a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.composite.shadow.no-transform.html b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.composite.shadow.no-transform.html
new file mode 100644
index 0000000000..bc7cfd314e
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.composite.shadow.no-transform.html
@@ -0,0 +1,83 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<link rel="match" href="2d.layer.global-states.filter.composite.shadow.no-transform-expected.html">
+<title>Canvas test: 2d.layer.global-states.filter.composite.shadow.no-transform</title>
+<h1 style="font-size: 20px;">2d.layer.global-states.filter.composite.shadow.no-transform</h1>
+<p class="desc">Checks that layers with filters correctly use global render states.</p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(2, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>no-globalAlpha</div>
+ <canvas id="canvas0" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas0");
+ const ctx = canvas.getContext('2d');
+
+ // No transform.
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ // No globalAlpha.
+ ctx.globalCompositeOperation = 'source-in';
+ ctx.shadowOffsetX = -7;
+ ctx.shadowOffsetY = 7;
+ ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
+ ctx.shadowBlur = 3;
+
+ ctx.beginLayer({filter: [
+ {name: 'dropShadow',
+ dx: 5, dy: 5, stdDeviation: 0, floodColor: '#00f'},
+ {name: 'componentTransfer',
+ funcA: {type: "table", tableValues: [0, 0.8]}}]});
+
+ 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();
+ </script>
+</span>
+
+<span>
+ <div>globalAlpha</div>
+ <canvas id="canvas1" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas1");
+ const ctx = canvas.getContext('2d');
+
+ // No transform.
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ ctx.globalAlpha = 0.75;
+ ctx.globalCompositeOperation = 'source-in';
+ ctx.shadowOffsetX = -7;
+ ctx.shadowOffsetY = 7;
+ ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
+ ctx.shadowBlur = 3;
+
+ ctx.beginLayer({filter: [
+ {name: 'dropShadow',
+ dx: 5, dy: 5, stdDeviation: 0, floodColor: '#00f'},
+ {name: 'componentTransfer',
+ funcA: {type: "table", tableValues: [0, 0.8]}}]});
+
+ 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();
+ </script>
+</span>
+
+</div>
diff --git a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.composite.shadow.rotation-expected.html b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.composite.shadow.rotation-expected.html
new file mode 100644
index 0000000000..e70fe3e92d
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.composite.shadow.rotation-expected.html
@@ -0,0 +1,108 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<title>Canvas test: 2d.layer.global-states.filter.composite.shadow.rotation</title>
+<h1 style="font-size: 20px;">2d.layer.global-states.filter.composite.shadow.rotation</h1>
+<p class="desc">Checks that layers with filters correctly use global render states.</p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(2, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>no-globalAlpha</div>
+ <canvas id="canvas0" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas0");
+ const ctx = canvas.getContext('2d');
+
+ const svg = `
+ <svg xmlns="http://www.w3.org/2000/svg"
+ width="90" height="90"
+ color-interpolation-filters="sRGB">
+ <filter id="filter" x="-100%" y="-100%" width="300%" height="300%">
+ <feDropShadow dx="5" dy="5" stdDeviation="0" flood-color="#00f" />
+ <feComponentTransfer>
+ <feFuncA type="table" tableValues="0 0.8"></feFuncA>
+ </feComponentTransfer>
+ </filter>
+ <g filter="url(#filter)">
+ <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>`;
+
+ const img = new Image();
+ img.width = 90;
+ img.height = 90;
+ img.onload = () => {
+ ctx.translate(50, 40);
+ ctx.rotate(Math.PI);
+ ctx.translate(-45, -45);
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ // No globalAlpha.
+ ctx.globalCompositeOperation = 'source-in';
+ ctx.shadowOffsetX = -7;
+ ctx.shadowOffsetY = 7;
+ ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
+ ctx.shadowBlur = 3;
+
+ ctx.drawImage(img, 0, 0);
+ };
+ img.src = 'data:image/svg+xml;base64,' + btoa(svg);
+ </script>
+</span>
+
+<span>
+ <div>globalAlpha</div>
+ <canvas id="canvas1" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas1");
+ const ctx = canvas.getContext('2d');
+
+ const svg = `
+ <svg xmlns="http://www.w3.org/2000/svg"
+ width="90" height="90"
+ color-interpolation-filters="sRGB">
+ <filter id="filter" x="-100%" y="-100%" width="300%" height="300%">
+ <feDropShadow dx="5" dy="5" stdDeviation="0" flood-color="#00f" />
+ <feComponentTransfer>
+ <feFuncA type="table" tableValues="0 0.8"></feFuncA>
+ </feComponentTransfer>
+ </filter>
+ <g filter="url(#filter)">
+ <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>`;
+
+ const img = new Image();
+ img.width = 90;
+ img.height = 90;
+ img.onload = () => {
+ ctx.translate(50, 40);
+ ctx.rotate(Math.PI);
+ ctx.translate(-45, -45);
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ ctx.globalAlpha = 0.75;
+ ctx.globalCompositeOperation = 'source-in';
+ ctx.shadowOffsetX = -7;
+ ctx.shadowOffsetY = 7;
+ ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
+ ctx.shadowBlur = 3;
+
+ ctx.drawImage(img, 0, 0);
+ };
+ img.src = 'data:image/svg+xml;base64,' + btoa(svg);
+ </script>
+</span>
+
+</div>
diff --git a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.composite.shadow.rotation.html b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.composite.shadow.rotation.html
new file mode 100644
index 0000000000..f304e9c8e8
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.composite.shadow.rotation.html
@@ -0,0 +1,87 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<link rel="match" href="2d.layer.global-states.filter.composite.shadow.rotation-expected.html">
+<title>Canvas test: 2d.layer.global-states.filter.composite.shadow.rotation</title>
+<h1 style="font-size: 20px;">2d.layer.global-states.filter.composite.shadow.rotation</h1>
+<p class="desc">Checks that layers with filters correctly use global render states.</p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(2, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>no-globalAlpha</div>
+ <canvas id="canvas0" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas0");
+ const ctx = canvas.getContext('2d');
+
+ ctx.translate(50, 40);
+ ctx.rotate(Math.PI);
+ ctx.translate(-45, -45);
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ // No globalAlpha.
+ ctx.globalCompositeOperation = 'source-in';
+ ctx.shadowOffsetX = -7;
+ ctx.shadowOffsetY = 7;
+ ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
+ ctx.shadowBlur = 3;
+
+ ctx.beginLayer({filter: [
+ {name: 'dropShadow',
+ dx: 5, dy: 5, stdDeviation: 0, floodColor: '#00f'},
+ {name: 'componentTransfer',
+ funcA: {type: "table", tableValues: [0, 0.8]}}]});
+
+ 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();
+ </script>
+</span>
+
+<span>
+ <div>globalAlpha</div>
+ <canvas id="canvas1" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas1");
+ const ctx = canvas.getContext('2d');
+
+ ctx.translate(50, 40);
+ ctx.rotate(Math.PI);
+ ctx.translate(-45, -45);
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ ctx.globalAlpha = 0.75;
+ ctx.globalCompositeOperation = 'source-in';
+ ctx.shadowOffsetX = -7;
+ ctx.shadowOffsetY = 7;
+ ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
+ ctx.shadowBlur = 3;
+
+ ctx.beginLayer({filter: [
+ {name: 'dropShadow',
+ dx: 5, dy: 5, stdDeviation: 0, floodColor: '#00f'},
+ {name: 'componentTransfer',
+ funcA: {type: "table", tableValues: [0, 0.8]}}]});
+
+ 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();
+ </script>
+</span>
+
+</div>
diff --git a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.copy.no-shadow.no-transform-expected.html b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.copy.no-shadow.no-transform-expected.html
new file mode 100644
index 0000000000..21aa241aca
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.copy.no-shadow.no-transform-expected.html
@@ -0,0 +1,98 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<title>Canvas test: 2d.layer.global-states.filter.copy.no-shadow.no-transform</title>
+<h1 style="font-size: 20px;">2d.layer.global-states.filter.copy.no-shadow.no-transform</h1>
+<p class="desc">Checks that layers with filters correctly use global render states.</p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(2, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>no-globalAlpha</div>
+ <canvas id="canvas0" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas0");
+ const ctx = canvas.getContext('2d');
+
+ const svg = `
+ <svg xmlns="http://www.w3.org/2000/svg"
+ width="90" height="90"
+ color-interpolation-filters="sRGB">
+ <filter id="filter" x="-100%" y="-100%" width="300%" height="300%">
+ <feDropShadow dx="5" dy="5" stdDeviation="0" flood-color="#00f" />
+ <feComponentTransfer>
+ <feFuncA type="table" tableValues="0 0.8"></feFuncA>
+ </feComponentTransfer>
+ </filter>
+ <g filter="url(#filter)">
+ <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>`;
+
+ const img = new Image();
+ img.width = 90;
+ img.height = 90;
+ img.onload = () => {
+ // No transform.
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ // No globalAlpha.
+ ctx.globalCompositeOperation = 'copy';
+ // No shadow.
+
+ ctx.drawImage(img, 0, 0);
+ };
+ img.src = 'data:image/svg+xml;base64,' + btoa(svg);
+ </script>
+</span>
+
+<span>
+ <div>globalAlpha</div>
+ <canvas id="canvas1" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas1");
+ const ctx = canvas.getContext('2d');
+
+ const svg = `
+ <svg xmlns="http://www.w3.org/2000/svg"
+ width="90" height="90"
+ color-interpolation-filters="sRGB">
+ <filter id="filter" x="-100%" y="-100%" width="300%" height="300%">
+ <feDropShadow dx="5" dy="5" stdDeviation="0" flood-color="#00f" />
+ <feComponentTransfer>
+ <feFuncA type="table" tableValues="0 0.8"></feFuncA>
+ </feComponentTransfer>
+ </filter>
+ <g filter="url(#filter)">
+ <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>`;
+
+ const img = new Image();
+ img.width = 90;
+ img.height = 90;
+ img.onload = () => {
+ // No transform.
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ ctx.globalAlpha = 0.75;
+ ctx.globalCompositeOperation = 'copy';
+ // No shadow.
+
+ ctx.drawImage(img, 0, 0);
+ };
+ img.src = 'data:image/svg+xml;base64,' + btoa(svg);
+ </script>
+</span>
+
+</div>
diff --git a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.copy.no-shadow.no-transform.html b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.copy.no-shadow.no-transform.html
new file mode 100644
index 0000000000..ac5c7303a8
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.copy.no-shadow.no-transform.html
@@ -0,0 +1,77 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<link rel="match" href="2d.layer.global-states.filter.copy.no-shadow.no-transform-expected.html">
+<title>Canvas test: 2d.layer.global-states.filter.copy.no-shadow.no-transform</title>
+<h1 style="font-size: 20px;">2d.layer.global-states.filter.copy.no-shadow.no-transform</h1>
+<p class="desc">Checks that layers with filters correctly use global render states.</p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(2, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>no-globalAlpha</div>
+ <canvas id="canvas0" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas0");
+ const ctx = canvas.getContext('2d');
+
+ // No transform.
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ // No globalAlpha.
+ ctx.globalCompositeOperation = 'copy';
+ // No shadow.
+
+ ctx.beginLayer({filter: [
+ {name: 'dropShadow',
+ dx: 5, dy: 5, stdDeviation: 0, floodColor: '#00f'},
+ {name: 'componentTransfer',
+ funcA: {type: "table", tableValues: [0, 0.8]}}]});
+
+ 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();
+ </script>
+</span>
+
+<span>
+ <div>globalAlpha</div>
+ <canvas id="canvas1" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas1");
+ const ctx = canvas.getContext('2d');
+
+ // No transform.
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ ctx.globalAlpha = 0.75;
+ ctx.globalCompositeOperation = 'copy';
+ // No shadow.
+
+ ctx.beginLayer({filter: [
+ {name: 'dropShadow',
+ dx: 5, dy: 5, stdDeviation: 0, floodColor: '#00f'},
+ {name: 'componentTransfer',
+ funcA: {type: "table", tableValues: [0, 0.8]}}]});
+
+ 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();
+ </script>
+</span>
+
+</div>
diff --git a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.copy.no-shadow.rotation-expected.html b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.copy.no-shadow.rotation-expected.html
new file mode 100644
index 0000000000..b2b46ee039
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.copy.no-shadow.rotation-expected.html
@@ -0,0 +1,102 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<title>Canvas test: 2d.layer.global-states.filter.copy.no-shadow.rotation</title>
+<h1 style="font-size: 20px;">2d.layer.global-states.filter.copy.no-shadow.rotation</h1>
+<p class="desc">Checks that layers with filters correctly use global render states.</p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(2, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>no-globalAlpha</div>
+ <canvas id="canvas0" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas0");
+ const ctx = canvas.getContext('2d');
+
+ const svg = `
+ <svg xmlns="http://www.w3.org/2000/svg"
+ width="90" height="90"
+ color-interpolation-filters="sRGB">
+ <filter id="filter" x="-100%" y="-100%" width="300%" height="300%">
+ <feDropShadow dx="5" dy="5" stdDeviation="0" flood-color="#00f" />
+ <feComponentTransfer>
+ <feFuncA type="table" tableValues="0 0.8"></feFuncA>
+ </feComponentTransfer>
+ </filter>
+ <g filter="url(#filter)">
+ <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>`;
+
+ const img = new Image();
+ img.width = 90;
+ img.height = 90;
+ img.onload = () => {
+ ctx.translate(50, 40);
+ ctx.rotate(Math.PI);
+ ctx.translate(-45, -45);
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ // No globalAlpha.
+ ctx.globalCompositeOperation = 'copy';
+ // No shadow.
+
+ ctx.drawImage(img, 0, 0);
+ };
+ img.src = 'data:image/svg+xml;base64,' + btoa(svg);
+ </script>
+</span>
+
+<span>
+ <div>globalAlpha</div>
+ <canvas id="canvas1" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas1");
+ const ctx = canvas.getContext('2d');
+
+ const svg = `
+ <svg xmlns="http://www.w3.org/2000/svg"
+ width="90" height="90"
+ color-interpolation-filters="sRGB">
+ <filter id="filter" x="-100%" y="-100%" width="300%" height="300%">
+ <feDropShadow dx="5" dy="5" stdDeviation="0" flood-color="#00f" />
+ <feComponentTransfer>
+ <feFuncA type="table" tableValues="0 0.8"></feFuncA>
+ </feComponentTransfer>
+ </filter>
+ <g filter="url(#filter)">
+ <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>`;
+
+ const img = new Image();
+ img.width = 90;
+ img.height = 90;
+ img.onload = () => {
+ ctx.translate(50, 40);
+ ctx.rotate(Math.PI);
+ ctx.translate(-45, -45);
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ ctx.globalAlpha = 0.75;
+ ctx.globalCompositeOperation = 'copy';
+ // No shadow.
+
+ ctx.drawImage(img, 0, 0);
+ };
+ img.src = 'data:image/svg+xml;base64,' + btoa(svg);
+ </script>
+</span>
+
+</div>
diff --git a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.copy.no-shadow.rotation.html b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.copy.no-shadow.rotation.html
new file mode 100644
index 0000000000..3158a2fff3
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.copy.no-shadow.rotation.html
@@ -0,0 +1,81 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<link rel="match" href="2d.layer.global-states.filter.copy.no-shadow.rotation-expected.html">
+<title>Canvas test: 2d.layer.global-states.filter.copy.no-shadow.rotation</title>
+<h1 style="font-size: 20px;">2d.layer.global-states.filter.copy.no-shadow.rotation</h1>
+<p class="desc">Checks that layers with filters correctly use global render states.</p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(2, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>no-globalAlpha</div>
+ <canvas id="canvas0" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas0");
+ const ctx = canvas.getContext('2d');
+
+ ctx.translate(50, 40);
+ ctx.rotate(Math.PI);
+ ctx.translate(-45, -45);
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ // No globalAlpha.
+ ctx.globalCompositeOperation = 'copy';
+ // No shadow.
+
+ ctx.beginLayer({filter: [
+ {name: 'dropShadow',
+ dx: 5, dy: 5, stdDeviation: 0, floodColor: '#00f'},
+ {name: 'componentTransfer',
+ funcA: {type: "table", tableValues: [0, 0.8]}}]});
+
+ 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();
+ </script>
+</span>
+
+<span>
+ <div>globalAlpha</div>
+ <canvas id="canvas1" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas1");
+ const ctx = canvas.getContext('2d');
+
+ ctx.translate(50, 40);
+ ctx.rotate(Math.PI);
+ ctx.translate(-45, -45);
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ ctx.globalAlpha = 0.75;
+ ctx.globalCompositeOperation = 'copy';
+ // No shadow.
+
+ ctx.beginLayer({filter: [
+ {name: 'dropShadow',
+ dx: 5, dy: 5, stdDeviation: 0, floodColor: '#00f'},
+ {name: 'componentTransfer',
+ funcA: {type: "table", tableValues: [0, 0.8]}}]});
+
+ 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();
+ </script>
+</span>
+
+</div>
diff --git a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.copy.shadow.no-transform-expected.html b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.copy.shadow.no-transform-expected.html
new file mode 100644
index 0000000000..d11326d5d6
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.copy.shadow.no-transform-expected.html
@@ -0,0 +1,104 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<title>Canvas test: 2d.layer.global-states.filter.copy.shadow.no-transform</title>
+<h1 style="font-size: 20px;">2d.layer.global-states.filter.copy.shadow.no-transform</h1>
+<p class="desc">Checks that layers with filters correctly use global render states.</p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(2, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>no-globalAlpha</div>
+ <canvas id="canvas0" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas0");
+ const ctx = canvas.getContext('2d');
+
+ const svg = `
+ <svg xmlns="http://www.w3.org/2000/svg"
+ width="90" height="90"
+ color-interpolation-filters="sRGB">
+ <filter id="filter" x="-100%" y="-100%" width="300%" height="300%">
+ <feDropShadow dx="5" dy="5" stdDeviation="0" flood-color="#00f" />
+ <feComponentTransfer>
+ <feFuncA type="table" tableValues="0 0.8"></feFuncA>
+ </feComponentTransfer>
+ </filter>
+ <g filter="url(#filter)">
+ <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>`;
+
+ const img = new Image();
+ img.width = 90;
+ img.height = 90;
+ img.onload = () => {
+ // No transform.
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ // No globalAlpha.
+ ctx.globalCompositeOperation = 'copy';
+ ctx.shadowOffsetX = -7;
+ ctx.shadowOffsetY = 7;
+ ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
+ ctx.shadowBlur = 3;
+
+ ctx.drawImage(img, 0, 0);
+ };
+ img.src = 'data:image/svg+xml;base64,' + btoa(svg);
+ </script>
+</span>
+
+<span>
+ <div>globalAlpha</div>
+ <canvas id="canvas1" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas1");
+ const ctx = canvas.getContext('2d');
+
+ const svg = `
+ <svg xmlns="http://www.w3.org/2000/svg"
+ width="90" height="90"
+ color-interpolation-filters="sRGB">
+ <filter id="filter" x="-100%" y="-100%" width="300%" height="300%">
+ <feDropShadow dx="5" dy="5" stdDeviation="0" flood-color="#00f" />
+ <feComponentTransfer>
+ <feFuncA type="table" tableValues="0 0.8"></feFuncA>
+ </feComponentTransfer>
+ </filter>
+ <g filter="url(#filter)">
+ <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>`;
+
+ const img = new Image();
+ img.width = 90;
+ img.height = 90;
+ img.onload = () => {
+ // No transform.
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ ctx.globalAlpha = 0.75;
+ ctx.globalCompositeOperation = 'copy';
+ ctx.shadowOffsetX = -7;
+ ctx.shadowOffsetY = 7;
+ ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
+ ctx.shadowBlur = 3;
+
+ ctx.drawImage(img, 0, 0);
+ };
+ img.src = 'data:image/svg+xml;base64,' + btoa(svg);
+ </script>
+</span>
+
+</div>
diff --git a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.copy.shadow.no-transform.html b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.copy.shadow.no-transform.html
new file mode 100644
index 0000000000..839ab13add
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.copy.shadow.no-transform.html
@@ -0,0 +1,83 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<link rel="match" href="2d.layer.global-states.filter.copy.shadow.no-transform-expected.html">
+<title>Canvas test: 2d.layer.global-states.filter.copy.shadow.no-transform</title>
+<h1 style="font-size: 20px;">2d.layer.global-states.filter.copy.shadow.no-transform</h1>
+<p class="desc">Checks that layers with filters correctly use global render states.</p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(2, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>no-globalAlpha</div>
+ <canvas id="canvas0" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas0");
+ const ctx = canvas.getContext('2d');
+
+ // No transform.
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ // No globalAlpha.
+ ctx.globalCompositeOperation = 'copy';
+ ctx.shadowOffsetX = -7;
+ ctx.shadowOffsetY = 7;
+ ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
+ ctx.shadowBlur = 3;
+
+ ctx.beginLayer({filter: [
+ {name: 'dropShadow',
+ dx: 5, dy: 5, stdDeviation: 0, floodColor: '#00f'},
+ {name: 'componentTransfer',
+ funcA: {type: "table", tableValues: [0, 0.8]}}]});
+
+ 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();
+ </script>
+</span>
+
+<span>
+ <div>globalAlpha</div>
+ <canvas id="canvas1" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas1");
+ const ctx = canvas.getContext('2d');
+
+ // No transform.
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ ctx.globalAlpha = 0.75;
+ ctx.globalCompositeOperation = 'copy';
+ ctx.shadowOffsetX = -7;
+ ctx.shadowOffsetY = 7;
+ ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
+ ctx.shadowBlur = 3;
+
+ ctx.beginLayer({filter: [
+ {name: 'dropShadow',
+ dx: 5, dy: 5, stdDeviation: 0, floodColor: '#00f'},
+ {name: 'componentTransfer',
+ funcA: {type: "table", tableValues: [0, 0.8]}}]});
+
+ 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();
+ </script>
+</span>
+
+</div>
diff --git a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.copy.shadow.rotation-expected.html b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.copy.shadow.rotation-expected.html
new file mode 100644
index 0000000000..3ac098c344
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.copy.shadow.rotation-expected.html
@@ -0,0 +1,108 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<title>Canvas test: 2d.layer.global-states.filter.copy.shadow.rotation</title>
+<h1 style="font-size: 20px;">2d.layer.global-states.filter.copy.shadow.rotation</h1>
+<p class="desc">Checks that layers with filters correctly use global render states.</p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(2, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>no-globalAlpha</div>
+ <canvas id="canvas0" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas0");
+ const ctx = canvas.getContext('2d');
+
+ const svg = `
+ <svg xmlns="http://www.w3.org/2000/svg"
+ width="90" height="90"
+ color-interpolation-filters="sRGB">
+ <filter id="filter" x="-100%" y="-100%" width="300%" height="300%">
+ <feDropShadow dx="5" dy="5" stdDeviation="0" flood-color="#00f" />
+ <feComponentTransfer>
+ <feFuncA type="table" tableValues="0 0.8"></feFuncA>
+ </feComponentTransfer>
+ </filter>
+ <g filter="url(#filter)">
+ <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>`;
+
+ const img = new Image();
+ img.width = 90;
+ img.height = 90;
+ img.onload = () => {
+ ctx.translate(50, 40);
+ ctx.rotate(Math.PI);
+ ctx.translate(-45, -45);
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ // No globalAlpha.
+ ctx.globalCompositeOperation = 'copy';
+ ctx.shadowOffsetX = -7;
+ ctx.shadowOffsetY = 7;
+ ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
+ ctx.shadowBlur = 3;
+
+ ctx.drawImage(img, 0, 0);
+ };
+ img.src = 'data:image/svg+xml;base64,' + btoa(svg);
+ </script>
+</span>
+
+<span>
+ <div>globalAlpha</div>
+ <canvas id="canvas1" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas1");
+ const ctx = canvas.getContext('2d');
+
+ const svg = `
+ <svg xmlns="http://www.w3.org/2000/svg"
+ width="90" height="90"
+ color-interpolation-filters="sRGB">
+ <filter id="filter" x="-100%" y="-100%" width="300%" height="300%">
+ <feDropShadow dx="5" dy="5" stdDeviation="0" flood-color="#00f" />
+ <feComponentTransfer>
+ <feFuncA type="table" tableValues="0 0.8"></feFuncA>
+ </feComponentTransfer>
+ </filter>
+ <g filter="url(#filter)">
+ <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>`;
+
+ const img = new Image();
+ img.width = 90;
+ img.height = 90;
+ img.onload = () => {
+ ctx.translate(50, 40);
+ ctx.rotate(Math.PI);
+ ctx.translate(-45, -45);
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ ctx.globalAlpha = 0.75;
+ ctx.globalCompositeOperation = 'copy';
+ ctx.shadowOffsetX = -7;
+ ctx.shadowOffsetY = 7;
+ ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
+ ctx.shadowBlur = 3;
+
+ ctx.drawImage(img, 0, 0);
+ };
+ img.src = 'data:image/svg+xml;base64,' + btoa(svg);
+ </script>
+</span>
+
+</div>
diff --git a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.copy.shadow.rotation.html b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.copy.shadow.rotation.html
new file mode 100644
index 0000000000..7c090165f5
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.copy.shadow.rotation.html
@@ -0,0 +1,87 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<link rel="match" href="2d.layer.global-states.filter.copy.shadow.rotation-expected.html">
+<title>Canvas test: 2d.layer.global-states.filter.copy.shadow.rotation</title>
+<h1 style="font-size: 20px;">2d.layer.global-states.filter.copy.shadow.rotation</h1>
+<p class="desc">Checks that layers with filters correctly use global render states.</p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(2, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>no-globalAlpha</div>
+ <canvas id="canvas0" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas0");
+ const ctx = canvas.getContext('2d');
+
+ ctx.translate(50, 40);
+ ctx.rotate(Math.PI);
+ ctx.translate(-45, -45);
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ // No globalAlpha.
+ ctx.globalCompositeOperation = 'copy';
+ ctx.shadowOffsetX = -7;
+ ctx.shadowOffsetY = 7;
+ ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
+ ctx.shadowBlur = 3;
+
+ ctx.beginLayer({filter: [
+ {name: 'dropShadow',
+ dx: 5, dy: 5, stdDeviation: 0, floodColor: '#00f'},
+ {name: 'componentTransfer',
+ funcA: {type: "table", tableValues: [0, 0.8]}}]});
+
+ 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();
+ </script>
+</span>
+
+<span>
+ <div>globalAlpha</div>
+ <canvas id="canvas1" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas1");
+ const ctx = canvas.getContext('2d');
+
+ ctx.translate(50, 40);
+ ctx.rotate(Math.PI);
+ ctx.translate(-45, -45);
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ ctx.globalAlpha = 0.75;
+ ctx.globalCompositeOperation = 'copy';
+ ctx.shadowOffsetX = -7;
+ ctx.shadowOffsetY = 7;
+ ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
+ ctx.shadowBlur = 3;
+
+ ctx.beginLayer({filter: [
+ {name: 'dropShadow',
+ dx: 5, dy: 5, stdDeviation: 0, floodColor: '#00f'},
+ {name: 'componentTransfer',
+ funcA: {type: "table", tableValues: [0, 0.8]}}]});
+
+ 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();
+ </script>
+</span>
+
+</div>
diff --git a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.no-composite-op.no-shadow.no-transform-expected.html b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.no-composite-op.no-shadow.no-transform-expected.html
new file mode 100644
index 0000000000..a445ae2c4a
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.no-composite-op.no-shadow.no-transform-expected.html
@@ -0,0 +1,98 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<title>Canvas test: 2d.layer.global-states.filter.no-composite-op.no-shadow.no-transform</title>
+<h1 style="font-size: 20px;">2d.layer.global-states.filter.no-composite-op.no-shadow.no-transform</h1>
+<p class="desc">Checks that layers with filters correctly use global render states.</p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(2, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>no-globalAlpha</div>
+ <canvas id="canvas0" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas0");
+ const ctx = canvas.getContext('2d');
+
+ const svg = `
+ <svg xmlns="http://www.w3.org/2000/svg"
+ width="90" height="90"
+ color-interpolation-filters="sRGB">
+ <filter id="filter" x="-100%" y="-100%" width="300%" height="300%">
+ <feDropShadow dx="5" dy="5" stdDeviation="0" flood-color="#00f" />
+ <feComponentTransfer>
+ <feFuncA type="table" tableValues="0 0.8"></feFuncA>
+ </feComponentTransfer>
+ </filter>
+ <g filter="url(#filter)">
+ <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>`;
+
+ const img = new Image();
+ img.width = 90;
+ img.height = 90;
+ img.onload = () => {
+ // No transform.
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ // No globalAlpha.
+ // No globalCompositeOperation.
+ // No shadow.
+
+ ctx.drawImage(img, 0, 0);
+ };
+ img.src = 'data:image/svg+xml;base64,' + btoa(svg);
+ </script>
+</span>
+
+<span>
+ <div>globalAlpha</div>
+ <canvas id="canvas1" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas1");
+ const ctx = canvas.getContext('2d');
+
+ const svg = `
+ <svg xmlns="http://www.w3.org/2000/svg"
+ width="90" height="90"
+ color-interpolation-filters="sRGB">
+ <filter id="filter" x="-100%" y="-100%" width="300%" height="300%">
+ <feDropShadow dx="5" dy="5" stdDeviation="0" flood-color="#00f" />
+ <feComponentTransfer>
+ <feFuncA type="table" tableValues="0 0.8"></feFuncA>
+ </feComponentTransfer>
+ </filter>
+ <g filter="url(#filter)">
+ <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>`;
+
+ const img = new Image();
+ img.width = 90;
+ img.height = 90;
+ img.onload = () => {
+ // No transform.
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ ctx.globalAlpha = 0.75;
+ // No globalCompositeOperation.
+ // No shadow.
+
+ ctx.drawImage(img, 0, 0);
+ };
+ img.src = 'data:image/svg+xml;base64,' + btoa(svg);
+ </script>
+</span>
+
+</div>
diff --git a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.no-composite-op.no-shadow.no-transform.html b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.no-composite-op.no-shadow.no-transform.html
new file mode 100644
index 0000000000..d2b2d806c4
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.no-composite-op.no-shadow.no-transform.html
@@ -0,0 +1,77 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<link rel="match" href="2d.layer.global-states.filter.no-composite-op.no-shadow.no-transform-expected.html">
+<title>Canvas test: 2d.layer.global-states.filter.no-composite-op.no-shadow.no-transform</title>
+<h1 style="font-size: 20px;">2d.layer.global-states.filter.no-composite-op.no-shadow.no-transform</h1>
+<p class="desc">Checks that layers with filters correctly use global render states.</p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(2, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>no-globalAlpha</div>
+ <canvas id="canvas0" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas0");
+ const ctx = canvas.getContext('2d');
+
+ // No transform.
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ // No globalAlpha.
+ // No globalCompositeOperation.
+ // No shadow.
+
+ ctx.beginLayer({filter: [
+ {name: 'dropShadow',
+ dx: 5, dy: 5, stdDeviation: 0, floodColor: '#00f'},
+ {name: 'componentTransfer',
+ funcA: {type: "table", tableValues: [0, 0.8]}}]});
+
+ 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();
+ </script>
+</span>
+
+<span>
+ <div>globalAlpha</div>
+ <canvas id="canvas1" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas1");
+ const ctx = canvas.getContext('2d');
+
+ // No transform.
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ ctx.globalAlpha = 0.75;
+ // No globalCompositeOperation.
+ // No shadow.
+
+ ctx.beginLayer({filter: [
+ {name: 'dropShadow',
+ dx: 5, dy: 5, stdDeviation: 0, floodColor: '#00f'},
+ {name: 'componentTransfer',
+ funcA: {type: "table", tableValues: [0, 0.8]}}]});
+
+ 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();
+ </script>
+</span>
+
+</div>
diff --git a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.no-composite-op.no-shadow.rotation-expected.html b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.no-composite-op.no-shadow.rotation-expected.html
new file mode 100644
index 0000000000..610c601b1c
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.no-composite-op.no-shadow.rotation-expected.html
@@ -0,0 +1,102 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<title>Canvas test: 2d.layer.global-states.filter.no-composite-op.no-shadow.rotation</title>
+<h1 style="font-size: 20px;">2d.layer.global-states.filter.no-composite-op.no-shadow.rotation</h1>
+<p class="desc">Checks that layers with filters correctly use global render states.</p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(2, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>no-globalAlpha</div>
+ <canvas id="canvas0" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas0");
+ const ctx = canvas.getContext('2d');
+
+ const svg = `
+ <svg xmlns="http://www.w3.org/2000/svg"
+ width="90" height="90"
+ color-interpolation-filters="sRGB">
+ <filter id="filter" x="-100%" y="-100%" width="300%" height="300%">
+ <feDropShadow dx="5" dy="5" stdDeviation="0" flood-color="#00f" />
+ <feComponentTransfer>
+ <feFuncA type="table" tableValues="0 0.8"></feFuncA>
+ </feComponentTransfer>
+ </filter>
+ <g filter="url(#filter)">
+ <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>`;
+
+ const img = new Image();
+ img.width = 90;
+ img.height = 90;
+ img.onload = () => {
+ ctx.translate(50, 40);
+ ctx.rotate(Math.PI);
+ ctx.translate(-45, -45);
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ // No globalAlpha.
+ // No globalCompositeOperation.
+ // No shadow.
+
+ ctx.drawImage(img, 0, 0);
+ };
+ img.src = 'data:image/svg+xml;base64,' + btoa(svg);
+ </script>
+</span>
+
+<span>
+ <div>globalAlpha</div>
+ <canvas id="canvas1" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas1");
+ const ctx = canvas.getContext('2d');
+
+ const svg = `
+ <svg xmlns="http://www.w3.org/2000/svg"
+ width="90" height="90"
+ color-interpolation-filters="sRGB">
+ <filter id="filter" x="-100%" y="-100%" width="300%" height="300%">
+ <feDropShadow dx="5" dy="5" stdDeviation="0" flood-color="#00f" />
+ <feComponentTransfer>
+ <feFuncA type="table" tableValues="0 0.8"></feFuncA>
+ </feComponentTransfer>
+ </filter>
+ <g filter="url(#filter)">
+ <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>`;
+
+ const img = new Image();
+ img.width = 90;
+ img.height = 90;
+ img.onload = () => {
+ ctx.translate(50, 40);
+ ctx.rotate(Math.PI);
+ ctx.translate(-45, -45);
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ ctx.globalAlpha = 0.75;
+ // No globalCompositeOperation.
+ // No shadow.
+
+ ctx.drawImage(img, 0, 0);
+ };
+ img.src = 'data:image/svg+xml;base64,' + btoa(svg);
+ </script>
+</span>
+
+</div>
diff --git a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.no-composite-op.no-shadow.rotation.html b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.no-composite-op.no-shadow.rotation.html
new file mode 100644
index 0000000000..afc4ebbd40
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.no-composite-op.no-shadow.rotation.html
@@ -0,0 +1,81 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<link rel="match" href="2d.layer.global-states.filter.no-composite-op.no-shadow.rotation-expected.html">
+<title>Canvas test: 2d.layer.global-states.filter.no-composite-op.no-shadow.rotation</title>
+<h1 style="font-size: 20px;">2d.layer.global-states.filter.no-composite-op.no-shadow.rotation</h1>
+<p class="desc">Checks that layers with filters correctly use global render states.</p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(2, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>no-globalAlpha</div>
+ <canvas id="canvas0" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas0");
+ const ctx = canvas.getContext('2d');
+
+ ctx.translate(50, 40);
+ ctx.rotate(Math.PI);
+ ctx.translate(-45, -45);
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ // No globalAlpha.
+ // No globalCompositeOperation.
+ // No shadow.
+
+ ctx.beginLayer({filter: [
+ {name: 'dropShadow',
+ dx: 5, dy: 5, stdDeviation: 0, floodColor: '#00f'},
+ {name: 'componentTransfer',
+ funcA: {type: "table", tableValues: [0, 0.8]}}]});
+
+ 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();
+ </script>
+</span>
+
+<span>
+ <div>globalAlpha</div>
+ <canvas id="canvas1" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas1");
+ const ctx = canvas.getContext('2d');
+
+ ctx.translate(50, 40);
+ ctx.rotate(Math.PI);
+ ctx.translate(-45, -45);
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ ctx.globalAlpha = 0.75;
+ // No globalCompositeOperation.
+ // No shadow.
+
+ ctx.beginLayer({filter: [
+ {name: 'dropShadow',
+ dx: 5, dy: 5, stdDeviation: 0, floodColor: '#00f'},
+ {name: 'componentTransfer',
+ funcA: {type: "table", tableValues: [0, 0.8]}}]});
+
+ 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();
+ </script>
+</span>
+
+</div>
diff --git a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.no-composite-op.shadow.no-transform-expected.html b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.no-composite-op.shadow.no-transform-expected.html
new file mode 100644
index 0000000000..6bd4501584
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.no-composite-op.shadow.no-transform-expected.html
@@ -0,0 +1,104 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<title>Canvas test: 2d.layer.global-states.filter.no-composite-op.shadow.no-transform</title>
+<h1 style="font-size: 20px;">2d.layer.global-states.filter.no-composite-op.shadow.no-transform</h1>
+<p class="desc">Checks that layers with filters correctly use global render states.</p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(2, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>no-globalAlpha</div>
+ <canvas id="canvas0" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas0");
+ const ctx = canvas.getContext('2d');
+
+ const svg = `
+ <svg xmlns="http://www.w3.org/2000/svg"
+ width="90" height="90"
+ color-interpolation-filters="sRGB">
+ <filter id="filter" x="-100%" y="-100%" width="300%" height="300%">
+ <feDropShadow dx="5" dy="5" stdDeviation="0" flood-color="#00f" />
+ <feComponentTransfer>
+ <feFuncA type="table" tableValues="0 0.8"></feFuncA>
+ </feComponentTransfer>
+ </filter>
+ <g filter="url(#filter)">
+ <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>`;
+
+ const img = new Image();
+ img.width = 90;
+ img.height = 90;
+ img.onload = () => {
+ // No transform.
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ // No globalAlpha.
+ // No globalCompositeOperation.
+ ctx.shadowOffsetX = -7;
+ ctx.shadowOffsetY = 7;
+ ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
+ ctx.shadowBlur = 3;
+
+ ctx.drawImage(img, 0, 0);
+ };
+ img.src = 'data:image/svg+xml;base64,' + btoa(svg);
+ </script>
+</span>
+
+<span>
+ <div>globalAlpha</div>
+ <canvas id="canvas1" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas1");
+ const ctx = canvas.getContext('2d');
+
+ const svg = `
+ <svg xmlns="http://www.w3.org/2000/svg"
+ width="90" height="90"
+ color-interpolation-filters="sRGB">
+ <filter id="filter" x="-100%" y="-100%" width="300%" height="300%">
+ <feDropShadow dx="5" dy="5" stdDeviation="0" flood-color="#00f" />
+ <feComponentTransfer>
+ <feFuncA type="table" tableValues="0 0.8"></feFuncA>
+ </feComponentTransfer>
+ </filter>
+ <g filter="url(#filter)">
+ <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>`;
+
+ const img = new Image();
+ img.width = 90;
+ img.height = 90;
+ img.onload = () => {
+ // No transform.
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ ctx.globalAlpha = 0.75;
+ // No globalCompositeOperation.
+ ctx.shadowOffsetX = -7;
+ ctx.shadowOffsetY = 7;
+ ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
+ ctx.shadowBlur = 3;
+
+ ctx.drawImage(img, 0, 0);
+ };
+ img.src = 'data:image/svg+xml;base64,' + btoa(svg);
+ </script>
+</span>
+
+</div>
diff --git a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.no-composite-op.shadow.no-transform.html b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.no-composite-op.shadow.no-transform.html
new file mode 100644
index 0000000000..93caac12fc
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.no-composite-op.shadow.no-transform.html
@@ -0,0 +1,83 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<link rel="match" href="2d.layer.global-states.filter.no-composite-op.shadow.no-transform-expected.html">
+<title>Canvas test: 2d.layer.global-states.filter.no-composite-op.shadow.no-transform</title>
+<h1 style="font-size: 20px;">2d.layer.global-states.filter.no-composite-op.shadow.no-transform</h1>
+<p class="desc">Checks that layers with filters correctly use global render states.</p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(2, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>no-globalAlpha</div>
+ <canvas id="canvas0" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas0");
+ const ctx = canvas.getContext('2d');
+
+ // No transform.
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ // No globalAlpha.
+ // No globalCompositeOperation.
+ ctx.shadowOffsetX = -7;
+ ctx.shadowOffsetY = 7;
+ ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
+ ctx.shadowBlur = 3;
+
+ ctx.beginLayer({filter: [
+ {name: 'dropShadow',
+ dx: 5, dy: 5, stdDeviation: 0, floodColor: '#00f'},
+ {name: 'componentTransfer',
+ funcA: {type: "table", tableValues: [0, 0.8]}}]});
+
+ 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();
+ </script>
+</span>
+
+<span>
+ <div>globalAlpha</div>
+ <canvas id="canvas1" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas1");
+ const ctx = canvas.getContext('2d');
+
+ // No transform.
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ ctx.globalAlpha = 0.75;
+ // No globalCompositeOperation.
+ ctx.shadowOffsetX = -7;
+ ctx.shadowOffsetY = 7;
+ ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
+ ctx.shadowBlur = 3;
+
+ ctx.beginLayer({filter: [
+ {name: 'dropShadow',
+ dx: 5, dy: 5, stdDeviation: 0, floodColor: '#00f'},
+ {name: 'componentTransfer',
+ funcA: {type: "table", tableValues: [0, 0.8]}}]});
+
+ 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();
+ </script>
+</span>
+
+</div>
diff --git a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.no-composite-op.shadow.rotation-expected.html b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.no-composite-op.shadow.rotation-expected.html
new file mode 100644
index 0000000000..b60a5526d9
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.no-composite-op.shadow.rotation-expected.html
@@ -0,0 +1,108 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<title>Canvas test: 2d.layer.global-states.filter.no-composite-op.shadow.rotation</title>
+<h1 style="font-size: 20px;">2d.layer.global-states.filter.no-composite-op.shadow.rotation</h1>
+<p class="desc">Checks that layers with filters correctly use global render states.</p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(2, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>no-globalAlpha</div>
+ <canvas id="canvas0" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas0");
+ const ctx = canvas.getContext('2d');
+
+ const svg = `
+ <svg xmlns="http://www.w3.org/2000/svg"
+ width="90" height="90"
+ color-interpolation-filters="sRGB">
+ <filter id="filter" x="-100%" y="-100%" width="300%" height="300%">
+ <feDropShadow dx="5" dy="5" stdDeviation="0" flood-color="#00f" />
+ <feComponentTransfer>
+ <feFuncA type="table" tableValues="0 0.8"></feFuncA>
+ </feComponentTransfer>
+ </filter>
+ <g filter="url(#filter)">
+ <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>`;
+
+ const img = new Image();
+ img.width = 90;
+ img.height = 90;
+ img.onload = () => {
+ ctx.translate(50, 40);
+ ctx.rotate(Math.PI);
+ ctx.translate(-45, -45);
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ // No globalAlpha.
+ // No globalCompositeOperation.
+ ctx.shadowOffsetX = -7;
+ ctx.shadowOffsetY = 7;
+ ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
+ ctx.shadowBlur = 3;
+
+ ctx.drawImage(img, 0, 0);
+ };
+ img.src = 'data:image/svg+xml;base64,' + btoa(svg);
+ </script>
+</span>
+
+<span>
+ <div>globalAlpha</div>
+ <canvas id="canvas1" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas1");
+ const ctx = canvas.getContext('2d');
+
+ const svg = `
+ <svg xmlns="http://www.w3.org/2000/svg"
+ width="90" height="90"
+ color-interpolation-filters="sRGB">
+ <filter id="filter" x="-100%" y="-100%" width="300%" height="300%">
+ <feDropShadow dx="5" dy="5" stdDeviation="0" flood-color="#00f" />
+ <feComponentTransfer>
+ <feFuncA type="table" tableValues="0 0.8"></feFuncA>
+ </feComponentTransfer>
+ </filter>
+ <g filter="url(#filter)">
+ <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>`;
+
+ const img = new Image();
+ img.width = 90;
+ img.height = 90;
+ img.onload = () => {
+ ctx.translate(50, 40);
+ ctx.rotate(Math.PI);
+ ctx.translate(-45, -45);
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ ctx.globalAlpha = 0.75;
+ // No globalCompositeOperation.
+ ctx.shadowOffsetX = -7;
+ ctx.shadowOffsetY = 7;
+ ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
+ ctx.shadowBlur = 3;
+
+ ctx.drawImage(img, 0, 0);
+ };
+ img.src = 'data:image/svg+xml;base64,' + btoa(svg);
+ </script>
+</span>
+
+</div>
diff --git a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.no-composite-op.shadow.rotation.html b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.no-composite-op.shadow.rotation.html
new file mode 100644
index 0000000000..6849a2f40d
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.no-composite-op.shadow.rotation.html
@@ -0,0 +1,87 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<link rel="match" href="2d.layer.global-states.filter.no-composite-op.shadow.rotation-expected.html">
+<title>Canvas test: 2d.layer.global-states.filter.no-composite-op.shadow.rotation</title>
+<h1 style="font-size: 20px;">2d.layer.global-states.filter.no-composite-op.shadow.rotation</h1>
+<p class="desc">Checks that layers with filters correctly use global render states.</p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(2, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>no-globalAlpha</div>
+ <canvas id="canvas0" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas0");
+ const ctx = canvas.getContext('2d');
+
+ ctx.translate(50, 40);
+ ctx.rotate(Math.PI);
+ ctx.translate(-45, -45);
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ // No globalAlpha.
+ // No globalCompositeOperation.
+ ctx.shadowOffsetX = -7;
+ ctx.shadowOffsetY = 7;
+ ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
+ ctx.shadowBlur = 3;
+
+ ctx.beginLayer({filter: [
+ {name: 'dropShadow',
+ dx: 5, dy: 5, stdDeviation: 0, floodColor: '#00f'},
+ {name: 'componentTransfer',
+ funcA: {type: "table", tableValues: [0, 0.8]}}]});
+
+ 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();
+ </script>
+</span>
+
+<span>
+ <div>globalAlpha</div>
+ <canvas id="canvas1" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas1");
+ const ctx = canvas.getContext('2d');
+
+ ctx.translate(50, 40);
+ ctx.rotate(Math.PI);
+ ctx.translate(-45, -45);
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ ctx.globalAlpha = 0.75;
+ // No globalCompositeOperation.
+ ctx.shadowOffsetX = -7;
+ ctx.shadowOffsetY = 7;
+ ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
+ ctx.shadowBlur = 3;
+
+ ctx.beginLayer({filter: [
+ {name: 'dropShadow',
+ dx: 5, dy: 5, stdDeviation: 0, floodColor: '#00f'},
+ {name: 'componentTransfer',
+ funcA: {type: "table", tableValues: [0, 0.8]}}]});
+
+ 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();
+ </script>
+</span>
+
+</div>
diff --git a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.no-global-states-expected.html b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.no-global-states-expected.html
deleted file mode 100644
index e56fe0b360..0000000000
--- a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.no-global-states-expected.html
+++ /dev/null
@@ -1,50 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<title>Canvas test: 2d.layer.global-states.filter.no-global-states</title>
-<h1>2d.layer.global-states.filter.no-global-states</h1>
-<p class="desc">Checks that layers with filters correctly use global render states.</p>
-<canvas id="canvas" width="200" height="200">
- <p class="fallback">FAIL (fallback content)</p>
-</canvas>
-<script>
- const canvas = document.getElementById("canvas");
- const ctx = canvas.getContext('2d');
-
- const svg = `
- <svg xmlns="http://www.w3.org/2000/svg"
- width="200" height="200"
- 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" />
- <feComponentTransfer>
- <feFuncA type="table" tableValues="0 0.7"></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)"/>
- </g>
- </svg>`;
-
- const img = new Image();
- img.width = 200;
- img.height = 200;
- img.onload = () => {
- ctx.fillStyle = 'rgba(0, 0, 255, 1)';
-
- var circle = new Path2D();
- circle.arc(90, 90, 45, 0, 2 * Math.PI);
- ctx.fill(circle);
-
- // No global states.
-
- ctx.drawImage(img, 0, 0);
- };
- img.src = 'data:image/svg+xml;base64,' + btoa(svg);
-</script>
diff --git a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.no-global-states.html b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.no-global-states.html
deleted file mode 100644
index 68f4d5004a..0000000000
--- a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.no-global-states.html
+++ /dev/null
@@ -1,37 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<link rel="match" href="2d.layer.global-states.filter.no-global-states-expected.html">
-<title>Canvas test: 2d.layer.global-states.filter.no-global-states</title>
-<h1>2d.layer.global-states.filter.no-global-states</h1>
-<p class="desc">Checks that layers with filters correctly use global render states.</p>
-<canvas id="canvas" width="200" height="200">
- <p class="fallback">FAIL (fallback content)</p>
-</canvas>
-<script>
- const canvas = document.getElementById("canvas");
- const ctx = canvas.getContext('2d');
-
- ctx.fillStyle = 'rgba(0, 0, 255, 1)';
-
- var circle = new Path2D();
- circle.arc(90, 90, 45, 0, 2 * Math.PI);
- ctx.fill(circle);
-
- // No global states.
-
- 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: 'componentTransfer',
- funcA: {type: "table", tableValues: [0, 0.7]}},
- {name: 'dropShadow', dx: 5, dy: 5, floodColor: '#81e'}]});
-
- 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.endLayer();
-</script>
diff --git a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.shadow-expected.html b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.shadow-expected.html
deleted file mode 100644
index 13ba2dd4cd..0000000000
--- a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.shadow-expected.html
+++ /dev/null
@@ -1,53 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<title>Canvas test: 2d.layer.global-states.filter.shadow</title>
-<h1>2d.layer.global-states.filter.shadow</h1>
-<p class="desc">Checks that layers with filters correctly use global render states.</p>
-<canvas id="canvas" width="200" height="200">
- <p class="fallback">FAIL (fallback content)</p>
-</canvas>
-<script>
- const canvas = document.getElementById("canvas");
- const ctx = canvas.getContext('2d');
-
- const svg = `
- <svg xmlns="http://www.w3.org/2000/svg"
- width="200" height="200"
- 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" />
- <feComponentTransfer>
- <feFuncA type="table" tableValues="0 0.7"></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)"/>
- </g>
- </svg>`;
-
- const img = new Image();
- img.width = 200;
- img.height = 200;
- img.onload = () => {
- ctx.fillStyle = 'rgba(0, 0, 255, 1)';
-
- var circle = new Path2D();
- circle.arc(90, 90, 45, 0, 2 * Math.PI);
- ctx.fill(circle);
-
- ctx.shadowOffsetX = -10;
- ctx.shadowOffsetY = 10;
- ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
- ctx.shadowBlur = 3;
-
- ctx.drawImage(img, 0, 0);
- };
- img.src = 'data:image/svg+xml;base64,' + btoa(svg);
-</script>
diff --git a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.shadow.html b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.shadow.html
deleted file mode 100644
index 9efcd9d4f7..0000000000
--- a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.filter.shadow.html
+++ /dev/null
@@ -1,40 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<link rel="match" href="2d.layer.global-states.filter.shadow-expected.html">
-<title>Canvas test: 2d.layer.global-states.filter.shadow</title>
-<h1>2d.layer.global-states.filter.shadow</h1>
-<p class="desc">Checks that layers with filters correctly use global render states.</p>
-<canvas id="canvas" width="200" height="200">
- <p class="fallback">FAIL (fallback content)</p>
-</canvas>
-<script>
- const canvas = document.getElementById("canvas");
- const ctx = canvas.getContext('2d');
-
- ctx.fillStyle = 'rgba(0, 0, 255, 1)';
-
- var circle = new Path2D();
- circle.arc(90, 90, 45, 0, 2 * Math.PI);
- ctx.fill(circle);
-
- ctx.shadowOffsetX = -10;
- ctx.shadowOffsetY = 10;
- ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
- ctx.shadowBlur = 3;
-
- 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: 'componentTransfer',
- funcA: {type: "table", tableValues: [0, 0.7]}},
- {name: 'dropShadow', dx: 5, dy: 5, floodColor: '#81e'}]});
-
- 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.endLayer();
-</script>
diff --git a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.no-composite-op.no-shadow.no-transform-expected.html b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.no-composite-op.no-shadow.no-transform-expected.html
new file mode 100644
index 0000000000..d1a799707f
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.no-composite-op.no-shadow.no-transform-expected.html
@@ -0,0 +1,72 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<title>Canvas test: 2d.layer.global-states.no-composite-op.no-shadow.no-transform</title>
+<h1 style="font-size: 20px;">2d.layer.global-states.no-composite-op.no-shadow.no-transform</h1>
+<p class="desc">Checks that layers correctly use global render states.</p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(2, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>no-globalAlpha</div>
+ <canvas id="canvas0" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas0");
+ const ctx = canvas.getContext('2d');
+
+ // No transform.
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ // No globalAlpha.
+ // No globalCompositeOperation.
+ // No shadow.
+
+ const canvas2 = document.createElement("canvas");
+ const ctx2 = canvas2.getContext("2d");
+
+ ctx2.globalCompositeOperation = 'screen';
+ ctx2.fillStyle = 'rgba(255, 0, 0, 1)';
+ ctx2.fillRect(10, 25, 40, 50);
+ ctx2.fillStyle = 'rgba(0, 255, 0, 1)';
+ ctx2.fillRect(30, 5, 50, 40);
+
+ ctx.drawImage(canvas2, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>globalAlpha</div>
+ <canvas id="canvas1" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas1");
+ const ctx = canvas.getContext('2d');
+
+ // No transform.
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ ctx.globalAlpha = 0.75;
+ // No globalCompositeOperation.
+ // No shadow.
+
+ const canvas2 = document.createElement("canvas");
+ const ctx2 = canvas2.getContext("2d");
+
+ ctx2.globalCompositeOperation = 'screen';
+ ctx2.fillStyle = 'rgba(255, 0, 0, 1)';
+ ctx2.fillRect(10, 25, 40, 50);
+ ctx2.fillStyle = 'rgba(0, 255, 0, 1)';
+ ctx2.fillRect(30, 5, 50, 40);
+
+ ctx.drawImage(canvas2, 0, 0);
+ </script>
+</span>
+
+</div>
diff --git a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.no-composite-op.no-shadow.no-transform.html b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.no-composite-op.no-shadow.no-transform.html
new file mode 100644
index 0000000000..f0fd2d19e3
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.no-composite-op.no-shadow.no-transform.html
@@ -0,0 +1,77 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<link rel="match" href="2d.layer.global-states.no-composite-op.no-shadow.no-transform-expected.html">
+<title>Canvas test: 2d.layer.global-states.no-composite-op.no-shadow.no-transform</title>
+<h1 style="font-size: 20px;">2d.layer.global-states.no-composite-op.no-shadow.no-transform</h1>
+<p class="desc">Checks that layers correctly use global render states.</p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(2, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>no-globalAlpha</div>
+ <canvas id="canvas0" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas0");
+ const ctx = canvas.getContext('2d');
+
+ // No transform.
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ // No globalAlpha.
+ // No globalCompositeOperation.
+ // No shadow.
+
+ ctx.beginLayer();
+
+ // Enable compositing in the layer to validate that draw calls in the layer
+ // won't individually composite with the background.
+ ctx.globalCompositeOperation = 'screen';
+
+ 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();
+ </script>
+</span>
+
+<span>
+ <div>globalAlpha</div>
+ <canvas id="canvas1" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas1");
+ const ctx = canvas.getContext('2d');
+
+ // No transform.
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ ctx.globalAlpha = 0.75;
+ // No globalCompositeOperation.
+ // No shadow.
+
+ ctx.beginLayer();
+
+ // Enable compositing in the layer to validate that draw calls in the layer
+ // won't individually composite with the background.
+ ctx.globalCompositeOperation = 'screen';
+
+ 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();
+ </script>
+</span>
+
+</div>
diff --git a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.no-composite-op.no-shadow.rotation-expected.html b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.no-composite-op.no-shadow.rotation-expected.html
new file mode 100644
index 0000000000..cc91a67faf
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.no-composite-op.no-shadow.rotation-expected.html
@@ -0,0 +1,76 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<title>Canvas test: 2d.layer.global-states.no-composite-op.no-shadow.rotation</title>
+<h1 style="font-size: 20px;">2d.layer.global-states.no-composite-op.no-shadow.rotation</h1>
+<p class="desc">Checks that layers correctly use global render states.</p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(2, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>no-globalAlpha</div>
+ <canvas id="canvas0" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas0");
+ const ctx = canvas.getContext('2d');
+
+ ctx.translate(50, 40);
+ ctx.rotate(Math.PI);
+ ctx.translate(-45, -45);
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ // No globalAlpha.
+ // No globalCompositeOperation.
+ // No shadow.
+
+ const canvas2 = document.createElement("canvas");
+ const ctx2 = canvas2.getContext("2d");
+
+ ctx2.globalCompositeOperation = 'screen';
+ ctx2.fillStyle = 'rgba(255, 0, 0, 1)';
+ ctx2.fillRect(10, 25, 40, 50);
+ ctx2.fillStyle = 'rgba(0, 255, 0, 1)';
+ ctx2.fillRect(30, 5, 50, 40);
+
+ ctx.drawImage(canvas2, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>globalAlpha</div>
+ <canvas id="canvas1" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas1");
+ const ctx = canvas.getContext('2d');
+
+ ctx.translate(50, 40);
+ ctx.rotate(Math.PI);
+ ctx.translate(-45, -45);
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ ctx.globalAlpha = 0.75;
+ // No globalCompositeOperation.
+ // No shadow.
+
+ const canvas2 = document.createElement("canvas");
+ const ctx2 = canvas2.getContext("2d");
+
+ ctx2.globalCompositeOperation = 'screen';
+ ctx2.fillStyle = 'rgba(255, 0, 0, 1)';
+ ctx2.fillRect(10, 25, 40, 50);
+ ctx2.fillStyle = 'rgba(0, 255, 0, 1)';
+ ctx2.fillRect(30, 5, 50, 40);
+
+ ctx.drawImage(canvas2, 0, 0);
+ </script>
+</span>
+
+</div>
diff --git a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.no-composite-op.no-shadow.rotation.html b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.no-composite-op.no-shadow.rotation.html
new file mode 100644
index 0000000000..7ab850023e
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.no-composite-op.no-shadow.rotation.html
@@ -0,0 +1,81 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<link rel="match" href="2d.layer.global-states.no-composite-op.no-shadow.rotation-expected.html">
+<title>Canvas test: 2d.layer.global-states.no-composite-op.no-shadow.rotation</title>
+<h1 style="font-size: 20px;">2d.layer.global-states.no-composite-op.no-shadow.rotation</h1>
+<p class="desc">Checks that layers correctly use global render states.</p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(2, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>no-globalAlpha</div>
+ <canvas id="canvas0" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas0");
+ const ctx = canvas.getContext('2d');
+
+ ctx.translate(50, 40);
+ ctx.rotate(Math.PI);
+ ctx.translate(-45, -45);
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ // No globalAlpha.
+ // No globalCompositeOperation.
+ // No shadow.
+
+ ctx.beginLayer();
+
+ // Enable compositing in the layer to validate that draw calls in the layer
+ // won't individually composite with the background.
+ ctx.globalCompositeOperation = 'screen';
+
+ 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();
+ </script>
+</span>
+
+<span>
+ <div>globalAlpha</div>
+ <canvas id="canvas1" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas1");
+ const ctx = canvas.getContext('2d');
+
+ ctx.translate(50, 40);
+ ctx.rotate(Math.PI);
+ ctx.translate(-45, -45);
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ ctx.globalAlpha = 0.75;
+ // No globalCompositeOperation.
+ // No shadow.
+
+ ctx.beginLayer();
+
+ // Enable compositing in the layer to validate that draw calls in the layer
+ // won't individually composite with the background.
+ ctx.globalCompositeOperation = 'screen';
+
+ 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();
+ </script>
+</span>
+
+</div>
diff --git a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.no-composite-op.shadow.no-transform-expected.html b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.no-composite-op.shadow.no-transform-expected.html
new file mode 100644
index 0000000000..02b239116c
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.no-composite-op.shadow.no-transform-expected.html
@@ -0,0 +1,78 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<title>Canvas test: 2d.layer.global-states.no-composite-op.shadow.no-transform</title>
+<h1 style="font-size: 20px;">2d.layer.global-states.no-composite-op.shadow.no-transform</h1>
+<p class="desc">Checks that layers correctly use global render states.</p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(2, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>no-globalAlpha</div>
+ <canvas id="canvas0" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas0");
+ const ctx = canvas.getContext('2d');
+
+ // No transform.
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ // No globalAlpha.
+ // No globalCompositeOperation.
+ ctx.shadowOffsetX = -7;
+ ctx.shadowOffsetY = 7;
+ ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
+ ctx.shadowBlur = 3;
+
+ const canvas2 = document.createElement("canvas");
+ const ctx2 = canvas2.getContext("2d");
+
+ ctx2.globalCompositeOperation = 'screen';
+ ctx2.fillStyle = 'rgba(255, 0, 0, 1)';
+ ctx2.fillRect(10, 25, 40, 50);
+ ctx2.fillStyle = 'rgba(0, 255, 0, 1)';
+ ctx2.fillRect(30, 5, 50, 40);
+
+ ctx.drawImage(canvas2, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>globalAlpha</div>
+ <canvas id="canvas1" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas1");
+ const ctx = canvas.getContext('2d');
+
+ // No transform.
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ ctx.globalAlpha = 0.75;
+ // No globalCompositeOperation.
+ ctx.shadowOffsetX = -7;
+ ctx.shadowOffsetY = 7;
+ ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
+ ctx.shadowBlur = 3;
+
+ const canvas2 = document.createElement("canvas");
+ const ctx2 = canvas2.getContext("2d");
+
+ ctx2.globalCompositeOperation = 'screen';
+ ctx2.fillStyle = 'rgba(255, 0, 0, 1)';
+ ctx2.fillRect(10, 25, 40, 50);
+ ctx2.fillStyle = 'rgba(0, 255, 0, 1)';
+ ctx2.fillRect(30, 5, 50, 40);
+
+ ctx.drawImage(canvas2, 0, 0);
+ </script>
+</span>
+
+</div>
diff --git a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.no-composite-op.shadow.no-transform.html b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.no-composite-op.shadow.no-transform.html
new file mode 100644
index 0000000000..9da1936c5d
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.no-composite-op.shadow.no-transform.html
@@ -0,0 +1,83 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<link rel="match" href="2d.layer.global-states.no-composite-op.shadow.no-transform-expected.html">
+<title>Canvas test: 2d.layer.global-states.no-composite-op.shadow.no-transform</title>
+<h1 style="font-size: 20px;">2d.layer.global-states.no-composite-op.shadow.no-transform</h1>
+<p class="desc">Checks that layers correctly use global render states.</p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(2, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>no-globalAlpha</div>
+ <canvas id="canvas0" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas0");
+ const ctx = canvas.getContext('2d');
+
+ // No transform.
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ // No globalAlpha.
+ // No globalCompositeOperation.
+ ctx.shadowOffsetX = -7;
+ ctx.shadowOffsetY = 7;
+ ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
+ ctx.shadowBlur = 3;
+
+ ctx.beginLayer();
+
+ // Enable compositing in the layer to validate that draw calls in the layer
+ // won't individually composite with the background.
+ ctx.globalCompositeOperation = 'screen';
+
+ 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();
+ </script>
+</span>
+
+<span>
+ <div>globalAlpha</div>
+ <canvas id="canvas1" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas1");
+ const ctx = canvas.getContext('2d');
+
+ // No transform.
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ ctx.globalAlpha = 0.75;
+ // No globalCompositeOperation.
+ ctx.shadowOffsetX = -7;
+ ctx.shadowOffsetY = 7;
+ ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
+ ctx.shadowBlur = 3;
+
+ ctx.beginLayer();
+
+ // Enable compositing in the layer to validate that draw calls in the layer
+ // won't individually composite with the background.
+ ctx.globalCompositeOperation = 'screen';
+
+ 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();
+ </script>
+</span>
+
+</div>
diff --git a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.no-composite-op.shadow.rotation-expected.html b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.no-composite-op.shadow.rotation-expected.html
new file mode 100644
index 0000000000..06f6a2dff3
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.no-composite-op.shadow.rotation-expected.html
@@ -0,0 +1,82 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<title>Canvas test: 2d.layer.global-states.no-composite-op.shadow.rotation</title>
+<h1 style="font-size: 20px;">2d.layer.global-states.no-composite-op.shadow.rotation</h1>
+<p class="desc">Checks that layers correctly use global render states.</p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(2, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>no-globalAlpha</div>
+ <canvas id="canvas0" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas0");
+ const ctx = canvas.getContext('2d');
+
+ ctx.translate(50, 40);
+ ctx.rotate(Math.PI);
+ ctx.translate(-45, -45);
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ // No globalAlpha.
+ // No globalCompositeOperation.
+ ctx.shadowOffsetX = -7;
+ ctx.shadowOffsetY = 7;
+ ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
+ ctx.shadowBlur = 3;
+
+ const canvas2 = document.createElement("canvas");
+ const ctx2 = canvas2.getContext("2d");
+
+ ctx2.globalCompositeOperation = 'screen';
+ ctx2.fillStyle = 'rgba(255, 0, 0, 1)';
+ ctx2.fillRect(10, 25, 40, 50);
+ ctx2.fillStyle = 'rgba(0, 255, 0, 1)';
+ ctx2.fillRect(30, 5, 50, 40);
+
+ ctx.drawImage(canvas2, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>globalAlpha</div>
+ <canvas id="canvas1" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas1");
+ const ctx = canvas.getContext('2d');
+
+ ctx.translate(50, 40);
+ ctx.rotate(Math.PI);
+ ctx.translate(-45, -45);
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ ctx.globalAlpha = 0.75;
+ // No globalCompositeOperation.
+ ctx.shadowOffsetX = -7;
+ ctx.shadowOffsetY = 7;
+ ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
+ ctx.shadowBlur = 3;
+
+ const canvas2 = document.createElement("canvas");
+ const ctx2 = canvas2.getContext("2d");
+
+ ctx2.globalCompositeOperation = 'screen';
+ ctx2.fillStyle = 'rgba(255, 0, 0, 1)';
+ ctx2.fillRect(10, 25, 40, 50);
+ ctx2.fillStyle = 'rgba(0, 255, 0, 1)';
+ ctx2.fillRect(30, 5, 50, 40);
+
+ ctx.drawImage(canvas2, 0, 0);
+ </script>
+</span>
+
+</div>
diff --git a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.no-composite-op.shadow.rotation.html b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.no-composite-op.shadow.rotation.html
new file mode 100644
index 0000000000..00ace7c54d
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.no-composite-op.shadow.rotation.html
@@ -0,0 +1,87 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<link rel="match" href="2d.layer.global-states.no-composite-op.shadow.rotation-expected.html">
+<title>Canvas test: 2d.layer.global-states.no-composite-op.shadow.rotation</title>
+<h1 style="font-size: 20px;">2d.layer.global-states.no-composite-op.shadow.rotation</h1>
+<p class="desc">Checks that layers correctly use global render states.</p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(2, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>no-globalAlpha</div>
+ <canvas id="canvas0" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas0");
+ const ctx = canvas.getContext('2d');
+
+ ctx.translate(50, 40);
+ ctx.rotate(Math.PI);
+ ctx.translate(-45, -45);
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ // No globalAlpha.
+ // No globalCompositeOperation.
+ ctx.shadowOffsetX = -7;
+ ctx.shadowOffsetY = 7;
+ ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
+ ctx.shadowBlur = 3;
+
+ ctx.beginLayer();
+
+ // Enable compositing in the layer to validate that draw calls in the layer
+ // won't individually composite with the background.
+ ctx.globalCompositeOperation = 'screen';
+
+ 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();
+ </script>
+</span>
+
+<span>
+ <div>globalAlpha</div>
+ <canvas id="canvas1" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas1");
+ const ctx = canvas.getContext('2d');
+
+ ctx.translate(50, 40);
+ ctx.rotate(Math.PI);
+ ctx.translate(-45, -45);
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ ctx.globalAlpha = 0.75;
+ // No globalCompositeOperation.
+ ctx.shadowOffsetX = -7;
+ ctx.shadowOffsetY = 7;
+ ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
+ ctx.shadowBlur = 3;
+
+ ctx.beginLayer();
+
+ // Enable compositing in the layer to validate that draw calls in the layer
+ // won't individually composite with the background.
+ ctx.globalCompositeOperation = 'screen';
+
+ 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();
+ </script>
+</span>
+
+</div>
diff --git a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.no-global-states-expected.html b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.no-global-states-expected.html
deleted file mode 100644
index b91a2ae8b5..0000000000
--- a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.no-global-states-expected.html
+++ /dev/null
@@ -1,31 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<title>Canvas test: 2d.layer.global-states.no-global-states</title>
-<h1>2d.layer.global-states.no-global-states</h1>
-<p class="desc">Checks that layers correctly use global render states.</p>
-<canvas id="canvas" width="200" height="200">
- <p class="fallback">FAIL (fallback content)</p>
-</canvas>
-<script>
- const canvas = document.getElementById("canvas");
- const ctx = canvas.getContext('2d');
-
- ctx.fillStyle = 'rgba(0, 0, 255, 1)';
-
- var circle = new Path2D();
- circle.arc(90, 90, 45, 0, 2 * Math.PI);
- ctx.fill(circle);
-
- // No global states.
-
- canvas2 = document.createElement("canvas");
- ctx2 = canvas2.getContext("2d");
-
- ctx2.globalCompositeOperation = 'screen';
- ctx2.fillStyle = 'rgba(225, 0, 0, 1)';
- ctx2.fillRect(50, 50, 75, 50);
- ctx2.fillStyle = 'rgba(0, 255, 0, 1)';
- ctx2.fillRect(70, 70, 75, 50);
-
- ctx.drawImage(canvas2, 0, 0);
-</script>
diff --git a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.no-global-states.html b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.no-global-states.html
deleted file mode 100644
index d561be2341..0000000000
--- a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.no-global-states.html
+++ /dev/null
@@ -1,34 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<link rel="match" href="2d.layer.global-states.no-global-states-expected.html">
-<title>Canvas test: 2d.layer.global-states.no-global-states</title>
-<h1>2d.layer.global-states.no-global-states</h1>
-<p class="desc">Checks that layers correctly use global render states.</p>
-<canvas id="canvas" width="200" height="200">
- <p class="fallback">FAIL (fallback content)</p>
-</canvas>
-<script>
- const canvas = document.getElementById("canvas");
- const ctx = canvas.getContext('2d');
-
- ctx.fillStyle = 'rgba(0, 0, 255, 1)';
-
- var circle = new Path2D();
- circle.arc(90, 90, 45, 0, 2 * Math.PI);
- ctx.fill(circle);
-
- // No global states.
-
- ctx.beginLayer();
-
- // Enable compositing in the layer to validate that draw calls in the layer
- // 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(0, 255, 0, 1)';
- ctx.fillRect(70, 70, 75, 50);
-
- ctx.endLayer();
-</script>
diff --git a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.shadow-expected.html b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.shadow-expected.html
deleted file mode 100644
index 835e9d420a..0000000000
--- a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.shadow-expected.html
+++ /dev/null
@@ -1,34 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<title>Canvas test: 2d.layer.global-states.shadow</title>
-<h1>2d.layer.global-states.shadow</h1>
-<p class="desc">Checks that layers correctly use global render states.</p>
-<canvas id="canvas" width="200" height="200">
- <p class="fallback">FAIL (fallback content)</p>
-</canvas>
-<script>
- const canvas = document.getElementById("canvas");
- const ctx = canvas.getContext('2d');
-
- ctx.fillStyle = 'rgba(0, 0, 255, 1)';
-
- var circle = new Path2D();
- circle.arc(90, 90, 45, 0, 2 * Math.PI);
- ctx.fill(circle);
-
- ctx.shadowOffsetX = -10;
- ctx.shadowOffsetY = 10;
- ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
- ctx.shadowBlur = 3;
-
- canvas2 = document.createElement("canvas");
- ctx2 = canvas2.getContext("2d");
-
- ctx2.globalCompositeOperation = 'screen';
- ctx2.fillStyle = 'rgba(225, 0, 0, 1)';
- ctx2.fillRect(50, 50, 75, 50);
- ctx2.fillStyle = 'rgba(0, 255, 0, 1)';
- ctx2.fillRect(70, 70, 75, 50);
-
- ctx.drawImage(canvas2, 0, 0);
-</script>
diff --git a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.shadow.html b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.shadow.html
deleted file mode 100644
index 209316164c..0000000000
--- a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.global-states.shadow.html
+++ /dev/null
@@ -1,37 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<link rel="match" href="2d.layer.global-states.shadow-expected.html">
-<title>Canvas test: 2d.layer.global-states.shadow</title>
-<h1>2d.layer.global-states.shadow</h1>
-<p class="desc">Checks that layers correctly use global render states.</p>
-<canvas id="canvas" width="200" height="200">
- <p class="fallback">FAIL (fallback content)</p>
-</canvas>
-<script>
- const canvas = document.getElementById("canvas");
- const ctx = canvas.getContext('2d');
-
- ctx.fillStyle = 'rgba(0, 0, 255, 1)';
-
- var circle = new Path2D();
- circle.arc(90, 90, 45, 0, 2 * Math.PI);
- ctx.fill(circle);
-
- ctx.shadowOffsetX = -10;
- ctx.shadowOffsetY = 10;
- ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
- ctx.shadowBlur = 3;
-
- ctx.beginLayer();
-
- // Enable compositing in the layer to validate that draw calls in the layer
- // 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(0, 255, 0, 1)';
- ctx.fillRect(70, 70, 75, 50);
-
- ctx.endLayer();
-</script>
diff --git a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.globalCompositeOperation-expected.html b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.globalCompositeOperation-expected.html
new file mode 100644
index 0000000000..02a8915c0b
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.globalCompositeOperation-expected.html
@@ -0,0 +1,910 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<title>Canvas test: 2d.layer.globalCompositeOperation</title>
+<h1 style="font-size: 20px;">2d.layer.globalCompositeOperation</h1>
+<p class="desc">Checks that layers work with all globalCompositeOperation values.</p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(7, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>source-over</div>
+ <canvas id="canvas0" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas0");
+ const ctx = canvas.getContext('2d');
+
+ 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 = 'source-over';
+ 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);
+ </script>
+</span>
+
+<span>
+ <div>source-in</div>
+ <canvas id="canvas1" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas1");
+ const ctx = canvas.getContext('2d');
+
+ 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 = 'source-in';
+ 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);
+ </script>
+</span>
+
+<span>
+ <div>source-atop</div>
+ <canvas id="canvas2" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas2");
+ const ctx = canvas.getContext('2d');
+
+ 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 = 'source-atop';
+ 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);
+ </script>
+</span>
+
+<span>
+ <div>destination-over</div>
+ <canvas id="canvas3" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas3");
+ const ctx = canvas.getContext('2d');
+
+ 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 = 'destination-over';
+ 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);
+ </script>
+</span>
+
+<span>
+ <div>destination-in</div>
+ <canvas id="canvas4" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas4");
+ const ctx = canvas.getContext('2d');
+
+ 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 = 'destination-in';
+ 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);
+ </script>
+</span>
+
+<span>
+ <div>destination-out</div>
+ <canvas id="canvas5" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas5");
+ const ctx = canvas.getContext('2d');
+
+ 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 = 'destination-out';
+ 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);
+ </script>
+</span>
+
+<span>
+ <div>destination-atop</div>
+ <canvas id="canvas6" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas6");
+ const ctx = canvas.getContext('2d');
+
+ 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 = 'destination-atop';
+ 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);
+ </script>
+</span>
+
+<span>
+ <div>lighter</div>
+ <canvas id="canvas7" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas7");
+ const ctx = canvas.getContext('2d');
+
+ 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 = 'lighter';
+ 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);
+ </script>
+</span>
+
+<span>
+ <div>copy</div>
+ <canvas id="canvas8" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas8");
+ const ctx = canvas.getContext('2d');
+
+ 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 = 'copy';
+ 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);
+ </script>
+</span>
+
+<span>
+ <div>xor</div>
+ <canvas id="canvas9" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas9");
+ const ctx = canvas.getContext('2d');
+
+ 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 = 'xor';
+ 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);
+ </script>
+</span>
+
+<span>
+ <div>multiply</div>
+ <canvas id="canvas10" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas10");
+ const ctx = canvas.getContext('2d');
+
+ 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 = 'multiply';
+ 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);
+ </script>
+</span>
+
+<span>
+ <div>screen</div>
+ <canvas id="canvas11" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas11");
+ const ctx = canvas.getContext('2d');
+
+ 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 = 'screen';
+ 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);
+ </script>
+</span>
+
+<span>
+ <div>overlay</div>
+ <canvas id="canvas12" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas12");
+ const ctx = canvas.getContext('2d');
+
+ 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 = 'overlay';
+ 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);
+ </script>
+</span>
+
+<span>
+ <div>darken</div>
+ <canvas id="canvas13" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas13");
+ const ctx = canvas.getContext('2d');
+
+ 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 = 'darken';
+ 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);
+ </script>
+</span>
+
+<span>
+ <div>lighten</div>
+ <canvas id="canvas14" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas14");
+ const ctx = canvas.getContext('2d');
+
+ 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 = 'lighten';
+ 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);
+ </script>
+</span>
+
+<span>
+ <div>color-dodge</div>
+ <canvas id="canvas15" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas15");
+ const ctx = canvas.getContext('2d');
+
+ 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 = 'color-dodge';
+ 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);
+ </script>
+</span>
+
+<span>
+ <div>color-burn</div>
+ <canvas id="canvas16" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas16");
+ const ctx = canvas.getContext('2d');
+
+ 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 = 'color-burn';
+ 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);
+ </script>
+</span>
+
+<span>
+ <div>hard-light</div>
+ <canvas id="canvas17" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas17");
+ const ctx = canvas.getContext('2d');
+
+ 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 = 'hard-light';
+ 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);
+ </script>
+</span>
+
+<span>
+ <div>soft-light</div>
+ <canvas id="canvas18" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas18");
+ const ctx = canvas.getContext('2d');
+
+ 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 = 'soft-light';
+ 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);
+ </script>
+</span>
+
+<span>
+ <div>difference</div>
+ <canvas id="canvas19" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas19");
+ const ctx = canvas.getContext('2d');
+
+ 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 = 'difference';
+ 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);
+ </script>
+</span>
+
+<span>
+ <div>exclusion</div>
+ <canvas id="canvas20" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas20");
+ const ctx = canvas.getContext('2d');
+
+ 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 = 'exclusion';
+ 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);
+ </script>
+</span>
+
+<span>
+ <div>hue</div>
+ <canvas id="canvas21" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas21");
+ const ctx = canvas.getContext('2d');
+
+ 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 = 'hue';
+ 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);
+ </script>
+</span>
+
+<span>
+ <div>saturation</div>
+ <canvas id="canvas22" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas22");
+ const ctx = canvas.getContext('2d');
+
+ 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 = 'saturation';
+ 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);
+ </script>
+</span>
+
+<span>
+ <div>color</div>
+ <canvas id="canvas23" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas23");
+ const ctx = canvas.getContext('2d');
+
+ 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 = 'color';
+ 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);
+ </script>
+</span>
+
+<span>
+ <div>luminosity</div>
+ <canvas id="canvas24" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas24");
+ const ctx = canvas.getContext('2d');
+
+ 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 = 'luminosity';
+ 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);
+ </script>
+</span>
+
+</div>
diff --git a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.globalCompositeOperation.html b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.globalCompositeOperation.html
new file mode 100644
index 0000000000..32809d852c
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.globalCompositeOperation.html
@@ -0,0 +1,861 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<link rel="match" href="2d.layer.globalCompositeOperation-expected.html">
+<title>Canvas test: 2d.layer.globalCompositeOperation</title>
+<h1 style="font-size: 20px;">2d.layer.globalCompositeOperation</h1>
+<p class="desc">Checks that layers work with all globalCompositeOperation values.</p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(7, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>source-over</div>
+ <canvas id="canvas0" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas0");
+ const ctx = canvas.getContext('2d');
+
+ 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 = 'source-over';
+ 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();
+ </script>
+</span>
+
+<span>
+ <div>source-in</div>
+ <canvas id="canvas1" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas1");
+ const ctx = canvas.getContext('2d');
+
+ 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 = 'source-in';
+ 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();
+ </script>
+</span>
+
+<span>
+ <div>source-atop</div>
+ <canvas id="canvas2" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas2");
+ const ctx = canvas.getContext('2d');
+
+ 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 = 'source-atop';
+ 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();
+ </script>
+</span>
+
+<span>
+ <div>destination-over</div>
+ <canvas id="canvas3" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas3");
+ const ctx = canvas.getContext('2d');
+
+ 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 = 'destination-over';
+ 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();
+ </script>
+</span>
+
+<span>
+ <div>destination-in</div>
+ <canvas id="canvas4" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas4");
+ const ctx = canvas.getContext('2d');
+
+ 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 = 'destination-in';
+ 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();
+ </script>
+</span>
+
+<span>
+ <div>destination-out</div>
+ <canvas id="canvas5" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas5");
+ const ctx = canvas.getContext('2d');
+
+ 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 = 'destination-out';
+ 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();
+ </script>
+</span>
+
+<span>
+ <div>destination-atop</div>
+ <canvas id="canvas6" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas6");
+ const ctx = canvas.getContext('2d');
+
+ 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 = 'destination-atop';
+ 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();
+ </script>
+</span>
+
+<span>
+ <div>lighter</div>
+ <canvas id="canvas7" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas7");
+ const ctx = canvas.getContext('2d');
+
+ 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 = 'lighter';
+ 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();
+ </script>
+</span>
+
+<span>
+ <div>copy</div>
+ <canvas id="canvas8" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas8");
+ const ctx = canvas.getContext('2d');
+
+ 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 = 'copy';
+ 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();
+ </script>
+</span>
+
+<span>
+ <div>xor</div>
+ <canvas id="canvas9" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas9");
+ const ctx = canvas.getContext('2d');
+
+ 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 = 'xor';
+ 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();
+ </script>
+</span>
+
+<span>
+ <div>multiply</div>
+ <canvas id="canvas10" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas10");
+ const ctx = canvas.getContext('2d');
+
+ 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 = 'multiply';
+ 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();
+ </script>
+</span>
+
+<span>
+ <div>screen</div>
+ <canvas id="canvas11" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas11");
+ const ctx = canvas.getContext('2d');
+
+ 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 = 'screen';
+ 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();
+ </script>
+</span>
+
+<span>
+ <div>overlay</div>
+ <canvas id="canvas12" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas12");
+ const ctx = canvas.getContext('2d');
+
+ 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 = 'overlay';
+ 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();
+ </script>
+</span>
+
+<span>
+ <div>darken</div>
+ <canvas id="canvas13" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas13");
+ const ctx = canvas.getContext('2d');
+
+ 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 = 'darken';
+ 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();
+ </script>
+</span>
+
+<span>
+ <div>lighten</div>
+ <canvas id="canvas14" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas14");
+ const ctx = canvas.getContext('2d');
+
+ 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 = 'lighten';
+ 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();
+ </script>
+</span>
+
+<span>
+ <div>color-dodge</div>
+ <canvas id="canvas15" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas15");
+ const ctx = canvas.getContext('2d');
+
+ 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 = 'color-dodge';
+ 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();
+ </script>
+</span>
+
+<span>
+ <div>color-burn</div>
+ <canvas id="canvas16" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas16");
+ const ctx = canvas.getContext('2d');
+
+ 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 = 'color-burn';
+ 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();
+ </script>
+</span>
+
+<span>
+ <div>hard-light</div>
+ <canvas id="canvas17" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas17");
+ const ctx = canvas.getContext('2d');
+
+ 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 = 'hard-light';
+ 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();
+ </script>
+</span>
+
+<span>
+ <div>soft-light</div>
+ <canvas id="canvas18" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas18");
+ const ctx = canvas.getContext('2d');
+
+ 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 = 'soft-light';
+ 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();
+ </script>
+</span>
+
+<span>
+ <div>difference</div>
+ <canvas id="canvas19" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas19");
+ const ctx = canvas.getContext('2d');
+
+ 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 = 'difference';
+ 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();
+ </script>
+</span>
+
+<span>
+ <div>exclusion</div>
+ <canvas id="canvas20" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas20");
+ const ctx = canvas.getContext('2d');
+
+ 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 = 'exclusion';
+ 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();
+ </script>
+</span>
+
+<span>
+ <div>hue</div>
+ <canvas id="canvas21" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas21");
+ const ctx = canvas.getContext('2d');
+
+ 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 = 'hue';
+ 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();
+ </script>
+</span>
+
+<span>
+ <div>saturation</div>
+ <canvas id="canvas22" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas22");
+ const ctx = canvas.getContext('2d');
+
+ 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 = 'saturation';
+ 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();
+ </script>
+</span>
+
+<span>
+ <div>color</div>
+ <canvas id="canvas23" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas23");
+ const ctx = canvas.getContext('2d');
+
+ 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 = 'color';
+ 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();
+ </script>
+</span>
+
+<span>
+ <div>luminosity</div>
+ <canvas id="canvas24" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas24");
+ const ctx = canvas.getContext('2d');
+
+ 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 = 'luminosity';
+ 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();
+ </script>
+</span>
+
+</div>
diff --git a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.invalid-calls.beginLayer-reset-endLayer.html b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.invalid-calls.beginLayer-reset-endLayer.html
index 74e05e1e48..1544bbcb82 100644
--- a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.invalid-calls.beginLayer-reset-endLayer.html
+++ b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.invalid-calls.beginLayer-reset-endLayer.html
@@ -16,8 +16,9 @@
<ul id="d"></ul>
<script>
-var t = async_test("Raises exception on beginLayer() + reset() + endLayer().");
-_addTest(function(canvas, ctx) {
+test(t => {
+ var canvas = document.getElementById('c');
+ var ctx = canvas.getContext('2d');
assert_throws_dom("INVALID_STATE_ERR", function() {
ctx.beginLayer();
@@ -25,6 +26,6 @@ _addTest(function(canvas, ctx) {
ctx.endLayer();
});
-});
+}, "Raises exception on beginLayer() + reset() + endLayer().");
</script>
diff --git a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.invalid-calls.beginLayer-restore.html b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.invalid-calls.beginLayer-restore.html
index 1979cb6c73..3d33fbf7fb 100644
--- a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.invalid-calls.beginLayer-restore.html
+++ b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.invalid-calls.beginLayer-restore.html
@@ -16,14 +16,15 @@
<ul id="d"></ul>
<script>
-var t = async_test("Raises exception on beginLayer() + restore().");
-_addTest(function(canvas, ctx) {
+test(t => {
+ var canvas = document.getElementById('c');
+ var ctx = canvas.getContext('2d');
assert_throws_dom("INVALID_STATE_ERR", function() {
ctx.beginLayer();
ctx.restore();
});
-});
+}, "Raises exception on beginLayer() + restore().");
</script>
diff --git a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.invalid-calls.beginLayer-save-endLayer.html b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.invalid-calls.beginLayer-save-endLayer.html
index c635ac75b9..e48f806f32 100644
--- a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.invalid-calls.beginLayer-save-endLayer.html
+++ b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.invalid-calls.beginLayer-save-endLayer.html
@@ -16,8 +16,9 @@
<ul id="d"></ul>
<script>
-var t = async_test("Raises exception on beginLayer() + save() + endLayer().");
-_addTest(function(canvas, ctx) {
+test(t => {
+ var canvas = document.getElementById('c');
+ var ctx = canvas.getContext('2d');
assert_throws_dom("INVALID_STATE_ERR", function() {
ctx.beginLayer();
@@ -25,6 +26,6 @@ _addTest(function(canvas, ctx) {
ctx.endLayer();
});
-});
+}, "Raises exception on beginLayer() + save() + endLayer().");
</script>
diff --git a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.invalid-calls.endLayer.html b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.invalid-calls.endLayer.html
index c39a352d65..2950de37bc 100644
--- a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.invalid-calls.endLayer.html
+++ b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.invalid-calls.endLayer.html
@@ -16,13 +16,14 @@
<ul id="d"></ul>
<script>
-var t = async_test("Raises exception on lone endLayer calls.");
-_addTest(function(canvas, ctx) {
+test(t => {
+ var canvas = document.getElementById('c');
+ var ctx = canvas.getContext('2d');
assert_throws_dom("INVALID_STATE_ERR", function() {
ctx.endLayer();
});
-});
+}, "Raises exception on lone endLayer calls.");
</script>
diff --git a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.invalid-calls.save-beginLayer-restore.html b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.invalid-calls.save-beginLayer-restore.html
index e2d4d56589..ff21610074 100644
--- a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.invalid-calls.save-beginLayer-restore.html
+++ b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.invalid-calls.save-beginLayer-restore.html
@@ -16,8 +16,9 @@
<ul id="d"></ul>
<script>
-var t = async_test("Raises exception on save() + beginLayer() + restore().");
-_addTest(function(canvas, ctx) {
+test(t => {
+ var canvas = document.getElementById('c');
+ var ctx = canvas.getContext('2d');
assert_throws_dom("INVALID_STATE_ERR", function() {
ctx.save();
@@ -25,6 +26,6 @@ _addTest(function(canvas, ctx) {
ctx.restore();
});
-});
+}, "Raises exception on save() + beginLayer() + restore().");
</script>
diff --git a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.invalid-calls.save-endLayer.html b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.invalid-calls.save-endLayer.html
index f4308e1191..5c6da4b5bc 100644
--- a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.invalid-calls.save-endLayer.html
+++ b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.invalid-calls.save-endLayer.html
@@ -16,14 +16,15 @@
<ul id="d"></ul>
<script>
-var t = async_test("Raises exception on save() + endLayer().");
-_addTest(function(canvas, ctx) {
+test(t => {
+ var canvas = document.getElementById('c');
+ var ctx = canvas.getContext('2d');
assert_throws_dom("INVALID_STATE_ERR", function() {
ctx.save();
ctx.endLayer();
});
-});
+}, "Raises exception on save() + endLayer().");
</script>
diff --git a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.malformed-operations-with-promises.createImageBitmap.html b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.malformed-operations-with-promises.createImageBitmap.html
deleted file mode 100644
index f1204aa61b..0000000000
--- a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.malformed-operations-with-promises.createImageBitmap.html
+++ /dev/null
@@ -1,34 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<title>Canvas test: 2d.layer.malformed-operations-with-promises.createImageBitmap</title>
-<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">
-<body class="show_output">
-
-<h1>2d.layer.malformed-operations-with-promises.createImageBitmap</h1>
-<p class="desc">Check that exceptions are thrown for operations that are malformed while layers are open.</p>
-
-
-<p class="output">Actual output:</p>
-<canvas id="c" class="output" width="200" height="200"><p class="fallback">FAIL (fallback content)</p></canvas>
-
-<ul id="d"></ul>
-<script>
-promise_test(async t => {
-
- var canvas = document.getElementById('c');
- var ctx = canvas.getContext('2d');
-
- // Shouldn't throw on its own.
- await createImageBitmap(canvas);
- // Make sure the exception isn't caused by calling the function twice.
- await createImageBitmap(canvas);
- // Calling again inside a layer should throw.
- ctx.beginLayer();
- await promise_rejects_dom(t, 'InvalidStateError', createImageBitmap(canvas));
-
-}, "Check that exceptions are thrown for operations that are malformed while layers are open.");
-</script>
-
diff --git a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.malformed-operations-with-promises.html b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.malformed-operations-with-promises.html
new file mode 100644
index 0000000000..8e81bffdfb
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.malformed-operations-with-promises.html
@@ -0,0 +1,40 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<title>Canvas test: 2d.layer.malformed-operations-with-promises</title>
+<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">
+
+<script>
+
+promise_test(async t => {
+ const canvas = document.createElement('canvas');
+ const ctx = canvas.getContext('2d');
+
+ // Shouldn't throw on its own.
+ await createImageBitmap(canvas);
+ // Make sure the exception isn't caused by calling the function twice.
+ await createImageBitmap(canvas);
+ // Calling again inside a layer should throw.
+ ctx.beginLayer();
+ await promise_rejects_dom(t, 'InvalidStateError',
+ createImageBitmap(canvas));
+}, "Throws if createImageBitmap is called while layers are open.");
+
+promise_test(async t => {
+ const canvas = document.createElement('canvas');
+ const ctx = canvas.getContext('2d');
+
+ // Shouldn't throw on its own.
+ await new Promise(resolve => canvas.toBlob(resolve));
+ // Make sure the exception isn't caused by calling the function twice.
+ await new Promise(resolve => canvas.toBlob(resolve));
+ // Calling again inside a layer should throw.
+ ctx.beginLayer();
+ await promise_rejects_dom(t, 'InvalidStateError',
+ new Promise(resolve => canvas.toBlob(resolve)));
+}, "Throws if toBlob is called while layers are open.");
+
+</script>
+</div>
diff --git a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.malformed-operations-with-promises.toBlob.html b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.malformed-operations-with-promises.toBlob.html
deleted file mode 100644
index 6c69bb3784..0000000000
--- a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.malformed-operations-with-promises.toBlob.html
+++ /dev/null
@@ -1,34 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<title>Canvas test: 2d.layer.malformed-operations-with-promises.toBlob</title>
-<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">
-<body class="show_output">
-
-<h1>2d.layer.malformed-operations-with-promises.toBlob</h1>
-<p class="desc">Check that exceptions are thrown for operations that are malformed while layers are open.</p>
-
-
-<p class="output">Actual output:</p>
-<canvas id="c" class="output" width="200" height="200"><p class="fallback">FAIL (fallback content)</p></canvas>
-
-<ul id="d"></ul>
-<script>
-promise_test(async t => {
-
- var canvas = document.getElementById('c');
- var ctx = canvas.getContext('2d');
-
- // Shouldn't throw on its own.
- await new Promise(resolve => canvas.toBlob(resolve));
- // Make sure the exception isn't caused by calling the function twice.
- await new Promise(resolve => canvas.toBlob(resolve));
- // Calling again inside a layer should throw.
- ctx.beginLayer();
- await promise_rejects_dom(t, 'InvalidStateError', new Promise(resolve => canvas.toBlob(resolve)));
-
-}, "Check that exceptions are thrown for operations that are malformed while layers are open.");
-</script>
-
diff --git a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.malformed-operations.createPattern.html b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.malformed-operations.createPattern.html
deleted file mode 100644
index f927b96524..0000000000
--- a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.malformed-operations.createPattern.html
+++ /dev/null
@@ -1,33 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<title>Canvas test: 2d.layer.malformed-operations.createPattern</title>
-<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">
-<body class="show_output">
-
-<h1>2d.layer.malformed-operations.createPattern</h1>
-<p class="desc">Check that exceptions are thrown for operations that are malformed while layers are open.</p>
-
-
-<p class="output">Actual output:</p>
-<canvas id="c" class="output" width="200" height="200"><p class="fallback">FAIL (fallback content)</p></canvas>
-
-<ul id="d"></ul>
-<script>
-var t = async_test("Check that exceptions are thrown for operations that are malformed while layers are open.");
-_addTest(function(canvas, ctx) {
-
- // Shouldn't throw on its own.
- ctx.createPattern(canvas, 'repeat');
- // Make sure the exception isn't caused by calling the function twice.
- ctx.createPattern(canvas, 'repeat');
- // Calling again inside a layer should throw.
- ctx.beginLayer();
- assert_throws_dom("InvalidStateError",
- () => ctx.createPattern(canvas, 'repeat'));
-
-});
-</script>
-
diff --git a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.malformed-operations.drawImage.html b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.malformed-operations.drawImage.html
deleted file mode 100644
index 8bcc89d38e..0000000000
--- a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.malformed-operations.drawImage.html
+++ /dev/null
@@ -1,35 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<title>Canvas test: 2d.layer.malformed-operations.drawImage</title>
-<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">
-<body class="show_output">
-
-<h1>2d.layer.malformed-operations.drawImage</h1>
-<p class="desc">Check that exceptions are thrown for operations that are malformed while layers are open.</p>
-
-
-<p class="output">Actual output:</p>
-<canvas id="c" class="output" width="200" height="200"><p class="fallback">FAIL (fallback content)</p></canvas>
-
-<ul id="d"></ul>
-<script>
-var t = async_test("Check that exceptions are thrown for operations that are malformed while layers are open.");
-_addTest(function(canvas, ctx) {
-
- const canvas2 = new OffscreenCanvas(200, 200);
- const ctx2 = canvas2.getContext('2d');
- // Shouldn't throw on its own.
- ctx2.drawImage(canvas, 0, 0);
- // Make sure the exception isn't caused by calling the function twice.
- ctx2.drawImage(canvas, 0, 0);
- // Calling again inside a layer should throw.
- ctx.beginLayer();
- assert_throws_dom("InvalidStateError",
- () => ctx2.drawImage(canvas, 0, 0));
-
-});
-</script>
-
diff --git a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.malformed-operations.getImageData.html b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.malformed-operations.getImageData.html
deleted file mode 100644
index 5dc3fcc017..0000000000
--- a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.malformed-operations.getImageData.html
+++ /dev/null
@@ -1,33 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<title>Canvas test: 2d.layer.malformed-operations.getImageData</title>
-<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">
-<body class="show_output">
-
-<h1>2d.layer.malformed-operations.getImageData</h1>
-<p class="desc">Check that exceptions are thrown for operations that are malformed while layers are open.</p>
-
-
-<p class="output">Actual output:</p>
-<canvas id="c" class="output" width="200" height="200"><p class="fallback">FAIL (fallback content)</p></canvas>
-
-<ul id="d"></ul>
-<script>
-var t = async_test("Check that exceptions are thrown for operations that are malformed while layers are open.");
-_addTest(function(canvas, ctx) {
-
- // Shouldn't throw on its own.
- ctx.getImageData(0, 0, 200, 200);
- // Make sure the exception isn't caused by calling the function twice.
- ctx.getImageData(0, 0, 200, 200);
- // Calling again inside a layer should throw.
- ctx.beginLayer();
- assert_throws_dom("InvalidStateError",
- () => ctx.getImageData(0, 0, 200, 200));
-
-});
-</script>
-
diff --git a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.malformed-operations.html b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.malformed-operations.html
new file mode 100644
index 0000000000..cf6e7a80db
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.malformed-operations.html
@@ -0,0 +1,87 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<title>Canvas test: 2d.layer.malformed-operations</title>
+<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">
+
+<script>
+
+test(t => {
+ const canvas = document.createElement('canvas');
+ const ctx = canvas.getContext('2d');
+
+ // Shouldn't throw on its own.
+ ctx.createPattern(canvas, 'repeat');
+ // Make sure the exception isn't caused by calling the function twice.
+ ctx.createPattern(canvas, 'repeat');
+ // Calling again inside a layer should throw.
+ ctx.beginLayer();
+ assert_throws_dom("InvalidStateError",
+ () => ctx.createPattern(canvas, 'repeat'));
+}, "Throws if createPattern is called while layers are open.");
+
+test(t => {
+ const canvas = document.createElement('canvas');
+ const ctx = canvas.getContext('2d');
+
+ const canvas2 = new OffscreenCanvas(200, 200);
+ const ctx2 = canvas2.getContext('2d');
+ // Shouldn't throw on its own.
+ ctx2.drawImage(canvas, 0, 0);
+ // Make sure the exception isn't caused by calling the function twice.
+ ctx2.drawImage(canvas, 0, 0);
+ // Calling again inside a layer should throw.
+ ctx.beginLayer();
+ assert_throws_dom("InvalidStateError",
+ () => ctx2.drawImage(canvas, 0, 0));
+}, "Throws if drawImage is called while layers are open.");
+
+test(t => {
+ const canvas = document.createElement('canvas');
+ const ctx = canvas.getContext('2d');
+
+ // Shouldn't throw on its own.
+ ctx.getImageData(0, 0, 200, 200);
+ // Make sure the exception isn't caused by calling the function twice.
+ ctx.getImageData(0, 0, 200, 200);
+ // Calling again inside a layer should throw.
+ ctx.beginLayer();
+ assert_throws_dom("InvalidStateError",
+ () => ctx.getImageData(0, 0, 200, 200));
+}, "Throws if getImageData is called while layers are open.");
+
+test(t => {
+ const canvas = document.createElement('canvas');
+ const ctx = canvas.getContext('2d');
+
+ const canvas2 = new OffscreenCanvas(200, 200);
+ const ctx2 = canvas2.getContext('2d')
+ const data = ctx2.getImageData(0, 0, 1, 1);
+ // Shouldn't throw on its own.
+ ctx.putImageData(data, 0, 0);
+ // Make sure the exception isn't caused by calling the function twice.
+ ctx.putImageData(data, 0, 0);
+ // Calling again inside a layer should throw.
+ ctx.beginLayer();
+ assert_throws_dom("InvalidStateError",
+ () => ctx.putImageData(data, 0, 0));
+}, "Throws if putImageData is called while layers are open.");
+
+test(t => {
+ const canvas = document.createElement('canvas');
+ const ctx = canvas.getContext('2d');
+
+ // Shouldn't throw on its own.
+ canvas.toDataURL();
+ // Make sure the exception isn't caused by calling the function twice.
+ canvas.toDataURL();
+ // Calling again inside a layer should throw.
+ ctx.beginLayer();
+ assert_throws_dom("InvalidStateError",
+ () => canvas.toDataURL());
+}, "Throws if toDataURL is called while layers are open.");
+
+</script>
+</div>
diff --git a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.malformed-operations.putImageData.html b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.malformed-operations.putImageData.html
deleted file mode 100644
index fd4fc262c2..0000000000
--- a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.malformed-operations.putImageData.html
+++ /dev/null
@@ -1,36 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<title>Canvas test: 2d.layer.malformed-operations.putImageData</title>
-<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">
-<body class="show_output">
-
-<h1>2d.layer.malformed-operations.putImageData</h1>
-<p class="desc">Check that exceptions are thrown for operations that are malformed while layers are open.</p>
-
-
-<p class="output">Actual output:</p>
-<canvas id="c" class="output" width="200" height="200"><p class="fallback">FAIL (fallback content)</p></canvas>
-
-<ul id="d"></ul>
-<script>
-var t = async_test("Check that exceptions are thrown for operations that are malformed while layers are open.");
-_addTest(function(canvas, ctx) {
-
- const canvas2 = new OffscreenCanvas(200, 200);
- const ctx2 = canvas2.getContext('2d')
- const data = ctx2.getImageData(0, 0, 1, 1);
- // Shouldn't throw on its own.
- ctx.putImageData(data, 0, 0);
- // Make sure the exception isn't caused by calling the function twice.
- ctx.putImageData(data, 0, 0);
- // Calling again inside a layer should throw.
- ctx.beginLayer();
- assert_throws_dom("InvalidStateError",
- () => ctx.putImageData(data, 0, 0));
-
-});
-</script>
-
diff --git a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.malformed-operations.toDataURL.html b/testing/web-platform/tests/html/canvas/element/layers/2d.layer.malformed-operations.toDataURL.html
deleted file mode 100644
index c9bb4f3875..0000000000
--- a/testing/web-platform/tests/html/canvas/element/layers/2d.layer.malformed-operations.toDataURL.html
+++ /dev/null
@@ -1,33 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<title>Canvas test: 2d.layer.malformed-operations.toDataURL</title>
-<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">
-<body class="show_output">
-
-<h1>2d.layer.malformed-operations.toDataURL</h1>
-<p class="desc">Check that exceptions are thrown for operations that are malformed while layers are open.</p>
-
-
-<p class="output">Actual output:</p>
-<canvas id="c" class="output" width="200" height="200"><p class="fallback">FAIL (fallback content)</p></canvas>
-
-<ul id="d"></ul>
-<script>
-var t = async_test("Check that exceptions are thrown for operations that are malformed while layers are open.");
-_addTest(function(canvas, ctx) {
-
- // Shouldn't throw on its own.
- canvas.toDataURL();
- // Make sure the exception isn't caused by calling the function twice.
- canvas.toDataURL();
- // Calling again inside a layer should throw.
- ctx.beginLayer();
- assert_throws_dom("InvalidStateError",
- () => canvas.toDataURL());
-
-});
-</script>
-
diff --git a/testing/web-platform/tests/html/canvas/element/manual/filters/svg-filter-lh-rlh-expected.html b/testing/web-platform/tests/html/canvas/element/manual/filters/svg-filter-lh-rlh-expected.html
new file mode 100644
index 0000000000..d183f6940d
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/element/manual/filters/svg-filter-lh-rlh-expected.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<html class="test-wait">
+<title>HTML Canvas reference: SVG filter using CSS font-relative line-height units</title>
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<style>
+:root {
+ font: 20px Ahem;
+}
+
+div {
+ display: inline-block;
+ width: 100px;
+ height: 100px;
+ background: green;
+}
+
+.r {
+ background: red;
+}
+</style>
+<div><div class="r" style="width: 48px;"></div></div><br>
+<div><div class="r" style="width: 24px;"></div></div>
diff --git a/testing/web-platform/tests/html/canvas/element/manual/filters/svg-filter-lh-rlh.html b/testing/web-platform/tests/html/canvas/element/manual/filters/svg-filter-lh-rlh.html
new file mode 100644
index 0000000000..b61193fb9f
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/element/manual/filters/svg-filter-lh-rlh.html
@@ -0,0 +1,32 @@
+<!DOCTYPE html>
+<html class="test-wait">
+<title>HTML Canvas test: SVG filter using CSS font-relative line-height units</title>
+<link rel="match" href="svg-filter-lh-rlh-expected.html"/>
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<style>
+:root {
+ font: 20px Ahem;
+}
+</style>
+<svg width="0" height="0">
+ <!-- https://html.spec.whatwg.org/multipage/canvas.html#working-with-externally-defined-svg-filters -->
+ <use href="./svg-filter.svg#filter-lh" />
+ <use href="./svg-filter.svg#filter-rlh" />
+</svg
+><canvas id="canvas-lh" width="100" height="100"></canvas><br
+><canvas id="canvas-rlh" width="100" height="100"></canvas>
+<script>
+function use_filter(canvas, filter_id) {
+ const ctx = canvas.getContext("2d");
+ ctx.font = "40px Ahem";
+ ctx.filter = `url(./svg-filter.svg#${filter_id})`;
+ ctx.fillStyle = "red";
+ ctx.fillRect(0, 0, 100, 100);
+}
+window.addEventListener("load", async () => {
+ use_filter(document.getElementById("canvas-lh"), "filter-lh");
+ use_filter(document.getElementById("canvas-rlh"), "filter-rlh");
+ document.documentElement.classList.remove('test-wait');
+});
+</script>
+</html>
diff --git a/testing/web-platform/tests/html/canvas/element/manual/filters/svg-filter.svg b/testing/web-platform/tests/html/canvas/element/manual/filters/svg-filter.svg
new file mode 100644
index 0000000000..a783a3eb15
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/element/manual/filters/svg-filter.svg
@@ -0,0 +1,10 @@
+<svg width="100" height="100" xmlns="http://www.w3.org/2000/svg">
+ <filter id="filter-lh">
+ <feFlood result="floodFill" x="1lh" y="0" width="100" height="100" flood-color="green" />
+ <feBlend in="SourceGraphic" in2="floodFill" mode="color-dodge" />
+ </filter>
+ <filter id="filter-rlh">
+ <feFlood result="floodFill" x="1rlh" y="0" width="100" height="100" flood-color="green" />
+ <feBlend in="SourceGraphic" in2="floodFill" mode="color-dodge" />
+ </filter>
+</svg>
diff --git a/testing/web-platform/tests/html/canvas/element/text/WEB_FEATURES.yml b/testing/web-platform/tests/html/canvas/element/text/WEB_FEATURES.yml
new file mode 100644
index 0000000000..1d9e4bab82
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/element/text/WEB_FEATURES.yml
@@ -0,0 +1,4 @@
+features:
+- name: canvas-text-baselines
+ files:
+ - 2d.text.measure.baselines.*
diff --git a/testing/web-platform/tests/html/canvas/offscreen/fill-and-stroke-styles/2d.fillStyle.parse.hsl-clamp-negative-saturation.html b/testing/web-platform/tests/html/canvas/offscreen/fill-and-stroke-styles/2d.fillStyle.parse.hsl-clamp-negative-saturation.html
new file mode 100644
index 0000000000..69277677b9
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/offscreen/fill-and-stroke-styles/2d.fillStyle.parse.hsl-clamp-negative-saturation.html
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<title>OffscreenCanvas test: 2d.fillStyle.parse.hsl-clamp-negative-saturation</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/html/canvas/resources/canvas-tests.js"></script>
+
+<h1>2d.fillStyle.parse.hsl-clamp-negative-saturation</h1>
+<p class="desc"></p>
+
+<p class="notes">
+<script>
+var t = async_test("");
+var t_pass = t.done.bind(t);
+var t_fail = t.step_func(function(reason) {
+ throw reason;
+});
+t.step(function() {
+
+ var canvas = new OffscreenCanvas(100, 50);
+ var ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = '#f00';
+ ctx.fillStyle = 'hsl(120, -200%, 49.9%)';
+ ctx.fillRect(0, 0, 100, 50);
+ _assertPixel(canvas, 50,25, 127,127,127,255);
+ t.done();
+
+});
+</script>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/fill-and-stroke-styles/2d.fillStyle.parse.hsl-clamp-negative-saturation.worker.js b/testing/web-platform/tests/html/canvas/offscreen/fill-and-stroke-styles/2d.fillStyle.parse.hsl-clamp-negative-saturation.worker.js
new file mode 100644
index 0000000000..7f1e91ddb7
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/offscreen/fill-and-stroke-styles/2d.fillStyle.parse.hsl-clamp-negative-saturation.worker.js
@@ -0,0 +1,25 @@
+// DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py.
+// OffscreenCanvas test in a worker:2d.fillStyle.parse.hsl-clamp-negative-saturation
+// Description:
+// Note:<p class="notes">
+
+importScripts("/resources/testharness.js");
+importScripts("/html/canvas/resources/canvas-tests.js");
+
+var t = async_test("");
+var t_pass = t.done.bind(t);
+var t_fail = t.step_func(function(reason) {
+ throw reason;
+});
+t.step(function() {
+
+ var canvas = new OffscreenCanvas(100, 50);
+ var ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = '#f00';
+ ctx.fillStyle = 'hsl(120, -200%, 49.9%)';
+ ctx.fillRect(0, 0, 100, 50);
+ _assertPixel(canvas, 50,25, 127,127,127,255);
+ t.done();
+});
+done();
diff --git a/testing/web-platform/tests/html/canvas/offscreen/fill-and-stroke-styles/2d.fillStyle.parse.hsla-clamp-alpha-1.html b/testing/web-platform/tests/html/canvas/offscreen/fill-and-stroke-styles/2d.fillStyle.parse.hsla-clamp-alpha-1.html
new file mode 100644
index 0000000000..5d73d34c9c
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/offscreen/fill-and-stroke-styles/2d.fillStyle.parse.hsla-clamp-alpha-1.html
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<title>OffscreenCanvas test: 2d.fillStyle.parse.hsla-clamp-alpha-1</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/html/canvas/resources/canvas-tests.js"></script>
+
+<h1>2d.fillStyle.parse.hsla-clamp-alpha-1</h1>
+<p class="desc"></p>
+
+<p class="notes">
+<script>
+var t = async_test("");
+var t_pass = t.done.bind(t);
+var t_fail = t.step_func(function(reason) {
+ throw reason;
+});
+t.step(function() {
+
+ var canvas = new OffscreenCanvas(100, 50);
+ var ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = '#f00';
+ ctx.fillStyle = 'hsla(120, 100%, 50%, 2)';
+ ctx.fillRect(0, 0, 100, 50);
+ _assertPixel(canvas, 50,25, 0,255,0,255);
+ t.done();
+
+});
+</script>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/fill-and-stroke-styles/2d.fillStyle.parse.hsla-clamp-alpha-1.worker.js b/testing/web-platform/tests/html/canvas/offscreen/fill-and-stroke-styles/2d.fillStyle.parse.hsla-clamp-alpha-1.worker.js
new file mode 100644
index 0000000000..7acb76d80b
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/offscreen/fill-and-stroke-styles/2d.fillStyle.parse.hsla-clamp-alpha-1.worker.js
@@ -0,0 +1,25 @@
+// DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py.
+// OffscreenCanvas test in a worker:2d.fillStyle.parse.hsla-clamp-alpha-1
+// Description:
+// Note:<p class="notes">
+
+importScripts("/resources/testharness.js");
+importScripts("/html/canvas/resources/canvas-tests.js");
+
+var t = async_test("");
+var t_pass = t.done.bind(t);
+var t_fail = t.step_func(function(reason) {
+ throw reason;
+});
+t.step(function() {
+
+ var canvas = new OffscreenCanvas(100, 50);
+ var ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = '#f00';
+ ctx.fillStyle = 'hsla(120, 100%, 50%, 2)';
+ ctx.fillRect(0, 0, 100, 50);
+ _assertPixel(canvas, 50,25, 0,255,0,255);
+ t.done();
+});
+done();
diff --git a/testing/web-platform/tests/html/canvas/offscreen/fill-and-stroke-styles/2d.fillStyle.parse.hsla-clamp-alpha-2.html b/testing/web-platform/tests/html/canvas/offscreen/fill-and-stroke-styles/2d.fillStyle.parse.hsla-clamp-alpha-2.html
new file mode 100644
index 0000000000..eaf7a6af89
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/offscreen/fill-and-stroke-styles/2d.fillStyle.parse.hsla-clamp-alpha-2.html
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<title>OffscreenCanvas test: 2d.fillStyle.parse.hsla-clamp-alpha-2</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/html/canvas/resources/canvas-tests.js"></script>
+
+<h1>2d.fillStyle.parse.hsla-clamp-alpha-2</h1>
+<p class="desc"></p>
+
+<p class="notes">
+<script>
+var t = async_test("");
+var t_pass = t.done.bind(t);
+var t_fail = t.step_func(function(reason) {
+ throw reason;
+});
+t.step(function() {
+
+ var canvas = new OffscreenCanvas(100, 50);
+ var ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = '#f00';
+ ctx.fillStyle = 'hsla(120, 100%, 0%, -2)';
+ ctx.fillRect(0, 0, 100, 50);
+ _assertPixel(canvas, 50,25, 0,0,0,0);
+ t.done();
+
+});
+</script>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/fill-and-stroke-styles/2d.fillStyle.parse.hsla-clamp-alpha-2.worker.js b/testing/web-platform/tests/html/canvas/offscreen/fill-and-stroke-styles/2d.fillStyle.parse.hsla-clamp-alpha-2.worker.js
new file mode 100644
index 0000000000..540b3ea15f
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/offscreen/fill-and-stroke-styles/2d.fillStyle.parse.hsla-clamp-alpha-2.worker.js
@@ -0,0 +1,25 @@
+// DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py.
+// OffscreenCanvas test in a worker:2d.fillStyle.parse.hsla-clamp-alpha-2
+// Description:
+// Note:<p class="notes">
+
+importScripts("/resources/testharness.js");
+importScripts("/html/canvas/resources/canvas-tests.js");
+
+var t = async_test("");
+var t_pass = t.done.bind(t);
+var t_fail = t.step_func(function(reason) {
+ throw reason;
+});
+t.step(function() {
+
+ var canvas = new OffscreenCanvas(100, 50);
+ var ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = '#f00';
+ ctx.fillStyle = 'hsla(120, 100%, 0%, -2)';
+ ctx.fillRect(0, 0, 100, 50);
+ _assertPixel(canvas, 50,25, 0,0,0,0);
+ t.done();
+});
+done();
diff --git a/testing/web-platform/tests/html/canvas/offscreen/fill-and-stroke-styles/2d.fillStyle.parse.hsla-clamp-negative-saturation.html b/testing/web-platform/tests/html/canvas/offscreen/fill-and-stroke-styles/2d.fillStyle.parse.hsla-clamp-negative-saturation.html
new file mode 100644
index 0000000000..04749fb4a7
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/offscreen/fill-and-stroke-styles/2d.fillStyle.parse.hsla-clamp-negative-saturation.html
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<title>OffscreenCanvas test: 2d.fillStyle.parse.hsla-clamp-negative-saturation</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/html/canvas/resources/canvas-tests.js"></script>
+
+<h1>2d.fillStyle.parse.hsla-clamp-negative-saturation</h1>
+<p class="desc"></p>
+
+<p class="notes">
+<script>
+var t = async_test("");
+var t_pass = t.done.bind(t);
+var t_fail = t.step_func(function(reason) {
+ throw reason;
+});
+t.step(function() {
+
+ var canvas = new OffscreenCanvas(100, 50);
+ var ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = '#f00';
+ ctx.fillStyle = 'hsla(120, -200%, 49.9%, 1)';
+ ctx.fillRect(0, 0, 100, 50);
+ _assertPixel(canvas, 50,25, 127,127,127,255);
+ t.done();
+
+});
+</script>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/fill-and-stroke-styles/2d.fillStyle.parse.hsla-clamp-negative-saturation.worker.js b/testing/web-platform/tests/html/canvas/offscreen/fill-and-stroke-styles/2d.fillStyle.parse.hsla-clamp-negative-saturation.worker.js
new file mode 100644
index 0000000000..f5fe6d4296
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/offscreen/fill-and-stroke-styles/2d.fillStyle.parse.hsla-clamp-negative-saturation.worker.js
@@ -0,0 +1,25 @@
+// DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py.
+// OffscreenCanvas test in a worker:2d.fillStyle.parse.hsla-clamp-negative-saturation
+// Description:
+// Note:<p class="notes">
+
+importScripts("/resources/testharness.js");
+importScripts("/html/canvas/resources/canvas-tests.js");
+
+var t = async_test("");
+var t_pass = t.done.bind(t);
+var t_fail = t.step_func(function(reason) {
+ throw reason;
+});
+t.step(function() {
+
+ var canvas = new OffscreenCanvas(100, 50);
+ var ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = '#f00';
+ ctx.fillStyle = 'hsla(120, -200%, 49.9%, 1)';
+ ctx.fillRect(0, 0, 100, 50);
+ _assertPixel(canvas, 50,25, 127,127,127,255);
+ t.done();
+});
+done();
diff --git a/testing/web-platform/tests/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.gaussianBlur.isotropic.tentative-expected.html b/testing/web-platform/tests/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.gaussianBlur.isotropic.tentative-expected.html
deleted file mode 100644
index dac31c97f1..0000000000
--- a/testing/web-platform/tests/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.gaussianBlur.isotropic.tentative-expected.html
+++ /dev/null
@@ -1,15 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<title>Canvas test: 2d.filter.canvasFilterObject.gaussianBlur.isotropic.tentative</title>
-<h1>2d.filter.canvasFilterObject.gaussianBlur.isotropic.tentative</h1>
-<p class="desc">Test CanvasFilter() with gaussianBlur.</p>
-
-<svg xmlns="http://www.w3.org/2000/svg"
- width="100" height="100"
- color-interpolation-filters="sRGB">
- <filter id="blur" x="-50%" y="-50%" width="200%" height="200%">
- <feGaussianBlur stdDeviation="4 4" />
- </filter>
- <rect x="25" y="25" width="50" height="50"
- fill="teal" filter="url(#blur)" />
-</svg>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.gaussianBlur.isotropic.tentative.html b/testing/web-platform/tests/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.gaussianBlur.isotropic.tentative.html
deleted file mode 100644
index 801e6fdb8c..0000000000
--- a/testing/web-platform/tests/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.gaussianBlur.isotropic.tentative.html
+++ /dev/null
@@ -1,23 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<link rel="match" href="2d.filter.canvasFilterObject.gaussianBlur.isotropic.tentative-expected.html">
-<title>Canvas test: 2d.filter.canvasFilterObject.gaussianBlur.isotropic.tentative</title>
-<h1>2d.filter.canvasFilterObject.gaussianBlur.isotropic.tentative</h1>
-<p class="desc">Test CanvasFilter() with gaussianBlur.</p>
-<canvas id="canvas" width="100" height="100">
- <p class="fallback">FAIL (fallback content)</p>
-</canvas>
-<script>
- const canvas = new OffscreenCanvas(100, 100);
- const ctx = canvas.getContext('2d');
-
- ctx.fillStyle = 'teal';
- ctx.filter = new CanvasFilter({
- name: 'gaussianBlur',
- stdDeviation: [4, 4],
- });
- ctx.fillRect(25, 25, 50, 50);
-
- const outputCanvas = document.getElementById("canvas");
- outputCanvas.getContext('2d').drawImage(canvas, 0, 0);
-</script>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.gaussianBlur.isotropic.tentative.w.html b/testing/web-platform/tests/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.gaussianBlur.isotropic.tentative.w.html
deleted file mode 100644
index 6c7c7f7649..0000000000
--- a/testing/web-platform/tests/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.gaussianBlur.isotropic.tentative.w.html
+++ /dev/null
@@ -1,37 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<html class="reftest-wait">
-<link rel="match" href="2d.filter.canvasFilterObject.gaussianBlur.isotropic.tentative-expected.html">
-<title>Canvas test: 2d.filter.canvasFilterObject.gaussianBlur.isotropic.tentative</title>
-<h1>2d.filter.canvasFilterObject.gaussianBlur.isotropic.tentative</h1>
-<p class="desc">Test CanvasFilter() with gaussianBlur.</p>
-<canvas id="canvas" width="100" height="100">
- <p class="fallback">FAIL (fallback content)</p>
-</canvas>
-<script id='myWorker' type='text/worker'>
- self.onmessage = function(e) {
- const canvas = new OffscreenCanvas(100, 100);
- const ctx = canvas.getContext('2d');
-
- ctx.fillStyle = 'teal';
- ctx.filter = new CanvasFilter({
- name: 'gaussianBlur',
- stdDeviation: [4, 4],
- });
- ctx.fillRect(25, 25, 50, 50);
-
- const bitmap = canvas.transferToImageBitmap();
- self.postMessage(bitmap, bitmap);
- };
-</script>
-<script>
- const blob = new Blob([document.getElementById('myWorker').textContent]);
- const worker = new Worker(URL.createObjectURL(blob));
- worker.addEventListener('message', msg => {
- const outputCtx = document.getElementById("canvas").getContext('2d');
- outputCtx.drawImage(msg.data, 0, 0);
- document.documentElement.classList.remove("reftest-wait");
- });
- worker.postMessage(null);
-</script>
-</html>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.gaussianBlur.mostly-x.tentative-expected.html b/testing/web-platform/tests/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.gaussianBlur.mostly-x.tentative-expected.html
deleted file mode 100644
index 88d0cb2de2..0000000000
--- a/testing/web-platform/tests/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.gaussianBlur.mostly-x.tentative-expected.html
+++ /dev/null
@@ -1,15 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<title>Canvas test: 2d.filter.canvasFilterObject.gaussianBlur.mostly-x.tentative</title>
-<h1>2d.filter.canvasFilterObject.gaussianBlur.mostly-x.tentative</h1>
-<p class="desc">Test CanvasFilter() with gaussianBlur.</p>
-
-<svg xmlns="http://www.w3.org/2000/svg"
- width="100" height="100"
- color-interpolation-filters="sRGB">
- <filter id="blur" x="-50%" y="-50%" width="200%" height="200%">
- <feGaussianBlur stdDeviation="4 1" />
- </filter>
- <rect x="25" y="25" width="50" height="50"
- fill="teal" filter="url(#blur)" />
-</svg>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.gaussianBlur.mostly-x.tentative.html b/testing/web-platform/tests/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.gaussianBlur.mostly-x.tentative.html
deleted file mode 100644
index ba986d8e7b..0000000000
--- a/testing/web-platform/tests/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.gaussianBlur.mostly-x.tentative.html
+++ /dev/null
@@ -1,23 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<link rel="match" href="2d.filter.canvasFilterObject.gaussianBlur.mostly-x.tentative-expected.html">
-<title>Canvas test: 2d.filter.canvasFilterObject.gaussianBlur.mostly-x.tentative</title>
-<h1>2d.filter.canvasFilterObject.gaussianBlur.mostly-x.tentative</h1>
-<p class="desc">Test CanvasFilter() with gaussianBlur.</p>
-<canvas id="canvas" width="100" height="100">
- <p class="fallback">FAIL (fallback content)</p>
-</canvas>
-<script>
- const canvas = new OffscreenCanvas(100, 100);
- const ctx = canvas.getContext('2d');
-
- ctx.fillStyle = 'teal';
- ctx.filter = new CanvasFilter({
- name: 'gaussianBlur',
- stdDeviation: [4, 1],
- });
- ctx.fillRect(25, 25, 50, 50);
-
- const outputCanvas = document.getElementById("canvas");
- outputCanvas.getContext('2d').drawImage(canvas, 0, 0);
-</script>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.gaussianBlur.mostly-x.tentative.w.html b/testing/web-platform/tests/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.gaussianBlur.mostly-x.tentative.w.html
deleted file mode 100644
index 86fe086327..0000000000
--- a/testing/web-platform/tests/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.gaussianBlur.mostly-x.tentative.w.html
+++ /dev/null
@@ -1,37 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<html class="reftest-wait">
-<link rel="match" href="2d.filter.canvasFilterObject.gaussianBlur.mostly-x.tentative-expected.html">
-<title>Canvas test: 2d.filter.canvasFilterObject.gaussianBlur.mostly-x.tentative</title>
-<h1>2d.filter.canvasFilterObject.gaussianBlur.mostly-x.tentative</h1>
-<p class="desc">Test CanvasFilter() with gaussianBlur.</p>
-<canvas id="canvas" width="100" height="100">
- <p class="fallback">FAIL (fallback content)</p>
-</canvas>
-<script id='myWorker' type='text/worker'>
- self.onmessage = function(e) {
- const canvas = new OffscreenCanvas(100, 100);
- const ctx = canvas.getContext('2d');
-
- ctx.fillStyle = 'teal';
- ctx.filter = new CanvasFilter({
- name: 'gaussianBlur',
- stdDeviation: [4, 1],
- });
- ctx.fillRect(25, 25, 50, 50);
-
- const bitmap = canvas.transferToImageBitmap();
- self.postMessage(bitmap, bitmap);
- };
-</script>
-<script>
- const blob = new Blob([document.getElementById('myWorker').textContent]);
- const worker = new Worker(URL.createObjectURL(blob));
- worker.addEventListener('message', msg => {
- const outputCtx = document.getElementById("canvas").getContext('2d');
- outputCtx.drawImage(msg.data, 0, 0);
- document.documentElement.classList.remove("reftest-wait");
- });
- worker.postMessage(null);
-</script>
-</html>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.gaussianBlur.mostly-y.tentative-expected.html b/testing/web-platform/tests/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.gaussianBlur.mostly-y.tentative-expected.html
deleted file mode 100644
index 744983d4ae..0000000000
--- a/testing/web-platform/tests/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.gaussianBlur.mostly-y.tentative-expected.html
+++ /dev/null
@@ -1,15 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<title>Canvas test: 2d.filter.canvasFilterObject.gaussianBlur.mostly-y.tentative</title>
-<h1>2d.filter.canvasFilterObject.gaussianBlur.mostly-y.tentative</h1>
-<p class="desc">Test CanvasFilter() with gaussianBlur.</p>
-
-<svg xmlns="http://www.w3.org/2000/svg"
- width="100" height="100"
- color-interpolation-filters="sRGB">
- <filter id="blur" x="-50%" y="-50%" width="200%" height="200%">
- <feGaussianBlur stdDeviation="1 4" />
- </filter>
- <rect x="25" y="25" width="50" height="50"
- fill="teal" filter="url(#blur)" />
-</svg>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.gaussianBlur.mostly-y.tentative.html b/testing/web-platform/tests/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.gaussianBlur.mostly-y.tentative.html
deleted file mode 100644
index 0265cfa6c4..0000000000
--- a/testing/web-platform/tests/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.gaussianBlur.mostly-y.tentative.html
+++ /dev/null
@@ -1,23 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<link rel="match" href="2d.filter.canvasFilterObject.gaussianBlur.mostly-y.tentative-expected.html">
-<title>Canvas test: 2d.filter.canvasFilterObject.gaussianBlur.mostly-y.tentative</title>
-<h1>2d.filter.canvasFilterObject.gaussianBlur.mostly-y.tentative</h1>
-<p class="desc">Test CanvasFilter() with gaussianBlur.</p>
-<canvas id="canvas" width="100" height="100">
- <p class="fallback">FAIL (fallback content)</p>
-</canvas>
-<script>
- const canvas = new OffscreenCanvas(100, 100);
- const ctx = canvas.getContext('2d');
-
- ctx.fillStyle = 'teal';
- ctx.filter = new CanvasFilter({
- name: 'gaussianBlur',
- stdDeviation: [1, 4],
- });
- ctx.fillRect(25, 25, 50, 50);
-
- const outputCanvas = document.getElementById("canvas");
- outputCanvas.getContext('2d').drawImage(canvas, 0, 0);
-</script>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.gaussianBlur.mostly-y.tentative.w.html b/testing/web-platform/tests/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.gaussianBlur.mostly-y.tentative.w.html
deleted file mode 100644
index c22b320857..0000000000
--- a/testing/web-platform/tests/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.gaussianBlur.mostly-y.tentative.w.html
+++ /dev/null
@@ -1,37 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<html class="reftest-wait">
-<link rel="match" href="2d.filter.canvasFilterObject.gaussianBlur.mostly-y.tentative-expected.html">
-<title>Canvas test: 2d.filter.canvasFilterObject.gaussianBlur.mostly-y.tentative</title>
-<h1>2d.filter.canvasFilterObject.gaussianBlur.mostly-y.tentative</h1>
-<p class="desc">Test CanvasFilter() with gaussianBlur.</p>
-<canvas id="canvas" width="100" height="100">
- <p class="fallback">FAIL (fallback content)</p>
-</canvas>
-<script id='myWorker' type='text/worker'>
- self.onmessage = function(e) {
- const canvas = new OffscreenCanvas(100, 100);
- const ctx = canvas.getContext('2d');
-
- ctx.fillStyle = 'teal';
- ctx.filter = new CanvasFilter({
- name: 'gaussianBlur',
- stdDeviation: [1, 4],
- });
- ctx.fillRect(25, 25, 50, 50);
-
- const bitmap = canvas.transferToImageBitmap();
- self.postMessage(bitmap, bitmap);
- };
-</script>
-<script>
- const blob = new Blob([document.getElementById('myWorker').textContent]);
- const worker = new Worker(URL.createObjectURL(blob));
- worker.addEventListener('message', msg => {
- const outputCtx = document.getElementById("canvas").getContext('2d');
- outputCtx.drawImage(msg.data, 0, 0);
- document.documentElement.classList.remove("reftest-wait");
- });
- worker.postMessage(null);
-</script>
-</html>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.gaussianBlur.tentative-expected.html b/testing/web-platform/tests/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.gaussianBlur.tentative-expected.html
new file mode 100644
index 0000000000..c1ca0ab46f
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.gaussianBlur.tentative-expected.html
@@ -0,0 +1,85 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<title>Canvas test: 2d.filter.canvasFilterObject.gaussianBlur.tentative</title>
+<h1 style="font-size: 20px;">2d.filter.canvasFilterObject.gaussianBlur.tentative</h1>
+<p class="desc">Test CanvasFilter() with gaussianBlur.</p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(5, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>x-only</div>
+ <div style="width: 100px; height: 100px; outline: 1px solid">
+ <svg xmlns="http://www.w3.org/2000/svg"
+ width="100" height="100"
+ color-interpolation-filters="sRGB">
+ <filter id="blur0" x="-50%" y="-50%" width="200%" height="200%">
+ <feGaussianBlur stdDeviation="4 0" />
+ </filter>
+ <rect x="25" y="25" width="50" height="50"
+ fill="teal" filter="url(#blur0)" />
+ </svg>
+ </div>
+</span>
+
+<span>
+ <div>mostly-x</div>
+ <div style="width: 100px; height: 100px; outline: 1px solid">
+ <svg xmlns="http://www.w3.org/2000/svg"
+ width="100" height="100"
+ color-interpolation-filters="sRGB">
+ <filter id="blur1" x="-50%" y="-50%" width="200%" height="200%">
+ <feGaussianBlur stdDeviation="4 1" />
+ </filter>
+ <rect x="25" y="25" width="50" height="50"
+ fill="teal" filter="url(#blur1)" />
+ </svg>
+ </div>
+</span>
+
+<span>
+ <div>isotropic</div>
+ <div style="width: 100px; height: 100px; outline: 1px solid">
+ <svg xmlns="http://www.w3.org/2000/svg"
+ width="100" height="100"
+ color-interpolation-filters="sRGB">
+ <filter id="blur2" x="-50%" y="-50%" width="200%" height="200%">
+ <feGaussianBlur stdDeviation="4 4" />
+ </filter>
+ <rect x="25" y="25" width="50" height="50"
+ fill="teal" filter="url(#blur2)" />
+ </svg>
+ </div>
+</span>
+
+<span>
+ <div>mostly-y</div>
+ <div style="width: 100px; height: 100px; outline: 1px solid">
+ <svg xmlns="http://www.w3.org/2000/svg"
+ width="100" height="100"
+ color-interpolation-filters="sRGB">
+ <filter id="blur3" x="-50%" y="-50%" width="200%" height="200%">
+ <feGaussianBlur stdDeviation="1 4" />
+ </filter>
+ <rect x="25" y="25" width="50" height="50"
+ fill="teal" filter="url(#blur3)" />
+ </svg>
+ </div>
+</span>
+
+<span>
+ <div>y-only</div>
+ <div style="width: 100px; height: 100px; outline: 1px solid">
+ <svg xmlns="http://www.w3.org/2000/svg"
+ width="100" height="100"
+ color-interpolation-filters="sRGB">
+ <filter id="blur4" x="-50%" y="-50%" width="200%" height="200%">
+ <feGaussianBlur stdDeviation="0 4" />
+ </filter>
+ <rect x="25" y="25" width="50" height="50"
+ fill="teal" filter="url(#blur4)" />
+ </svg>
+ </div>
+</span>
+
+</div>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.gaussianBlur.tentative.html b/testing/web-platform/tests/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.gaussianBlur.tentative.html
new file mode 100644
index 0000000000..8e7ea3f727
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.gaussianBlur.tentative.html
@@ -0,0 +1,121 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<link rel="match" href="2d.filter.canvasFilterObject.gaussianBlur.tentative-expected.html">
+<title>Canvas test: 2d.filter.canvasFilterObject.gaussianBlur.tentative</title>
+<h1 style="font-size: 20px;">2d.filter.canvasFilterObject.gaussianBlur.tentative</h1>
+<p class="desc">Test CanvasFilter() with gaussianBlur.</p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(5, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>x-only</div>
+ <canvas id="canvas0" width="100" height="100" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(100, 100);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'teal';
+ ctx.filter = new CanvasFilter({
+ name: 'gaussianBlur',
+ stdDeviation: [4, 0],
+ });
+ ctx.fillRect(25, 25, 50, 50);
+
+ const outputCanvas = document.getElementById("canvas0");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>mostly-x</div>
+ <canvas id="canvas1" width="100" height="100" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(100, 100);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'teal';
+ ctx.filter = new CanvasFilter({
+ name: 'gaussianBlur',
+ stdDeviation: [4, 1],
+ });
+ ctx.fillRect(25, 25, 50, 50);
+
+ const outputCanvas = document.getElementById("canvas1");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>isotropic</div>
+ <canvas id="canvas2" width="100" height="100" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(100, 100);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'teal';
+ ctx.filter = new CanvasFilter({
+ name: 'gaussianBlur',
+ stdDeviation: [4, 4],
+ });
+ ctx.fillRect(25, 25, 50, 50);
+
+ const outputCanvas = document.getElementById("canvas2");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>mostly-y</div>
+ <canvas id="canvas3" width="100" height="100" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(100, 100);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'teal';
+ ctx.filter = new CanvasFilter({
+ name: 'gaussianBlur',
+ stdDeviation: [1, 4],
+ });
+ ctx.fillRect(25, 25, 50, 50);
+
+ const outputCanvas = document.getElementById("canvas3");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>y-only</div>
+ <canvas id="canvas4" width="100" height="100" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(100, 100);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'teal';
+ ctx.filter = new CanvasFilter({
+ name: 'gaussianBlur',
+ stdDeviation: [0, 4],
+ });
+ ctx.fillRect(25, 25, 50, 50);
+
+ const outputCanvas = document.getElementById("canvas4");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+</div>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.gaussianBlur.tentative.w.html b/testing/web-platform/tests/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.gaussianBlur.tentative.w.html
new file mode 100644
index 0000000000..71626ac46e
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.gaussianBlur.tentative.w.html
@@ -0,0 +1,194 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<html class="reftest-wait">
+<link rel="match" href="2d.filter.canvasFilterObject.gaussianBlur.tentative-expected.html">
+<title>Canvas test: 2d.filter.canvasFilterObject.gaussianBlur.tentative</title>
+<h1 style="font-size: 20px;">2d.filter.canvasFilterObject.gaussianBlur.tentative</h1>
+<p class="desc">Test CanvasFilter() with gaussianBlur.</p>
+<script>pending_tests = 5;</script>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(5, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>x-only</div>
+ <canvas id="canvas0" width="100" height="100" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script id="myWorker0" type="text/worker">
+ self.onmessage = function(e) {
+ const canvas = new OffscreenCanvas(100, 100);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'teal';
+ ctx.filter = new CanvasFilter({
+ name: 'gaussianBlur',
+ stdDeviation: [4, 0],
+ });
+ ctx.fillRect(25, 25, 50, 50);
+
+ const bitmap = canvas.transferToImageBitmap();
+ self.postMessage(bitmap, bitmap);
+ };
+ </script>
+ <script type="module">
+ const blob = new Blob([document.getElementById('myWorker0').textContent]);
+ const worker = new Worker(URL.createObjectURL(blob));
+ worker.addEventListener('message', msg => {
+ const outputCanvas = document.getElementById('canvas0');
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(msg.data, 0, 0);
+ if (--pending_tests == 0) {
+ document.documentElement.classList.remove('reftest-wait');
+ }
+ });
+ worker.postMessage(null);
+ </script>
+</span>
+
+<span>
+ <div>mostly-x</div>
+ <canvas id="canvas1" width="100" height="100" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script id="myWorker1" type="text/worker">
+ self.onmessage = function(e) {
+ const canvas = new OffscreenCanvas(100, 100);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'teal';
+ ctx.filter = new CanvasFilter({
+ name: 'gaussianBlur',
+ stdDeviation: [4, 1],
+ });
+ ctx.fillRect(25, 25, 50, 50);
+
+ const bitmap = canvas.transferToImageBitmap();
+ self.postMessage(bitmap, bitmap);
+ };
+ </script>
+ <script type="module">
+ const blob = new Blob([document.getElementById('myWorker1').textContent]);
+ const worker = new Worker(URL.createObjectURL(blob));
+ worker.addEventListener('message', msg => {
+ const outputCanvas = document.getElementById('canvas1');
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(msg.data, 0, 0);
+ if (--pending_tests == 0) {
+ document.documentElement.classList.remove('reftest-wait');
+ }
+ });
+ worker.postMessage(null);
+ </script>
+</span>
+
+<span>
+ <div>isotropic</div>
+ <canvas id="canvas2" width="100" height="100" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script id="myWorker2" type="text/worker">
+ self.onmessage = function(e) {
+ const canvas = new OffscreenCanvas(100, 100);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'teal';
+ ctx.filter = new CanvasFilter({
+ name: 'gaussianBlur',
+ stdDeviation: [4, 4],
+ });
+ ctx.fillRect(25, 25, 50, 50);
+
+ const bitmap = canvas.transferToImageBitmap();
+ self.postMessage(bitmap, bitmap);
+ };
+ </script>
+ <script type="module">
+ const blob = new Blob([document.getElementById('myWorker2').textContent]);
+ const worker = new Worker(URL.createObjectURL(blob));
+ worker.addEventListener('message', msg => {
+ const outputCanvas = document.getElementById('canvas2');
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(msg.data, 0, 0);
+ if (--pending_tests == 0) {
+ document.documentElement.classList.remove('reftest-wait');
+ }
+ });
+ worker.postMessage(null);
+ </script>
+</span>
+
+<span>
+ <div>mostly-y</div>
+ <canvas id="canvas3" width="100" height="100" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script id="myWorker3" type="text/worker">
+ self.onmessage = function(e) {
+ const canvas = new OffscreenCanvas(100, 100);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'teal';
+ ctx.filter = new CanvasFilter({
+ name: 'gaussianBlur',
+ stdDeviation: [1, 4],
+ });
+ ctx.fillRect(25, 25, 50, 50);
+
+ const bitmap = canvas.transferToImageBitmap();
+ self.postMessage(bitmap, bitmap);
+ };
+ </script>
+ <script type="module">
+ const blob = new Blob([document.getElementById('myWorker3').textContent]);
+ const worker = new Worker(URL.createObjectURL(blob));
+ worker.addEventListener('message', msg => {
+ const outputCanvas = document.getElementById('canvas3');
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(msg.data, 0, 0);
+ if (--pending_tests == 0) {
+ document.documentElement.classList.remove('reftest-wait');
+ }
+ });
+ worker.postMessage(null);
+ </script>
+</span>
+
+<span>
+ <div>y-only</div>
+ <canvas id="canvas4" width="100" height="100" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script id="myWorker4" type="text/worker">
+ self.onmessage = function(e) {
+ const canvas = new OffscreenCanvas(100, 100);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'teal';
+ ctx.filter = new CanvasFilter({
+ name: 'gaussianBlur',
+ stdDeviation: [0, 4],
+ });
+ ctx.fillRect(25, 25, 50, 50);
+
+ const bitmap = canvas.transferToImageBitmap();
+ self.postMessage(bitmap, bitmap);
+ };
+ </script>
+ <script type="module">
+ const blob = new Blob([document.getElementById('myWorker4').textContent]);
+ const worker = new Worker(URL.createObjectURL(blob));
+ worker.addEventListener('message', msg => {
+ const outputCanvas = document.getElementById('canvas4');
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(msg.data, 0, 0);
+ if (--pending_tests == 0) {
+ document.documentElement.classList.remove('reftest-wait');
+ }
+ });
+ worker.postMessage(null);
+ </script>
+</span>
+
+</div>
+</html>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.gaussianBlur.x-only.tentative-expected.html b/testing/web-platform/tests/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.gaussianBlur.x-only.tentative-expected.html
deleted file mode 100644
index e611113e42..0000000000
--- a/testing/web-platform/tests/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.gaussianBlur.x-only.tentative-expected.html
+++ /dev/null
@@ -1,15 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<title>Canvas test: 2d.filter.canvasFilterObject.gaussianBlur.x-only.tentative</title>
-<h1>2d.filter.canvasFilterObject.gaussianBlur.x-only.tentative</h1>
-<p class="desc">Test CanvasFilter() with gaussianBlur.</p>
-
-<svg xmlns="http://www.w3.org/2000/svg"
- width="100" height="100"
- color-interpolation-filters="sRGB">
- <filter id="blur" x="-50%" y="-50%" width="200%" height="200%">
- <feGaussianBlur stdDeviation="4 0" />
- </filter>
- <rect x="25" y="25" width="50" height="50"
- fill="teal" filter="url(#blur)" />
-</svg>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.gaussianBlur.x-only.tentative.html b/testing/web-platform/tests/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.gaussianBlur.x-only.tentative.html
deleted file mode 100644
index 3ed8e9ddf9..0000000000
--- a/testing/web-platform/tests/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.gaussianBlur.x-only.tentative.html
+++ /dev/null
@@ -1,23 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<link rel="match" href="2d.filter.canvasFilterObject.gaussianBlur.x-only.tentative-expected.html">
-<title>Canvas test: 2d.filter.canvasFilterObject.gaussianBlur.x-only.tentative</title>
-<h1>2d.filter.canvasFilterObject.gaussianBlur.x-only.tentative</h1>
-<p class="desc">Test CanvasFilter() with gaussianBlur.</p>
-<canvas id="canvas" width="100" height="100">
- <p class="fallback">FAIL (fallback content)</p>
-</canvas>
-<script>
- const canvas = new OffscreenCanvas(100, 100);
- const ctx = canvas.getContext('2d');
-
- ctx.fillStyle = 'teal';
- ctx.filter = new CanvasFilter({
- name: 'gaussianBlur',
- stdDeviation: [4, 0],
- });
- ctx.fillRect(25, 25, 50, 50);
-
- const outputCanvas = document.getElementById("canvas");
- outputCanvas.getContext('2d').drawImage(canvas, 0, 0);
-</script>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.gaussianBlur.x-only.tentative.w.html b/testing/web-platform/tests/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.gaussianBlur.x-only.tentative.w.html
deleted file mode 100644
index 35cbc1b365..0000000000
--- a/testing/web-platform/tests/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.gaussianBlur.x-only.tentative.w.html
+++ /dev/null
@@ -1,37 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<html class="reftest-wait">
-<link rel="match" href="2d.filter.canvasFilterObject.gaussianBlur.x-only.tentative-expected.html">
-<title>Canvas test: 2d.filter.canvasFilterObject.gaussianBlur.x-only.tentative</title>
-<h1>2d.filter.canvasFilterObject.gaussianBlur.x-only.tentative</h1>
-<p class="desc">Test CanvasFilter() with gaussianBlur.</p>
-<canvas id="canvas" width="100" height="100">
- <p class="fallback">FAIL (fallback content)</p>
-</canvas>
-<script id='myWorker' type='text/worker'>
- self.onmessage = function(e) {
- const canvas = new OffscreenCanvas(100, 100);
- const ctx = canvas.getContext('2d');
-
- ctx.fillStyle = 'teal';
- ctx.filter = new CanvasFilter({
- name: 'gaussianBlur',
- stdDeviation: [4, 0],
- });
- ctx.fillRect(25, 25, 50, 50);
-
- const bitmap = canvas.transferToImageBitmap();
- self.postMessage(bitmap, bitmap);
- };
-</script>
-<script>
- const blob = new Blob([document.getElementById('myWorker').textContent]);
- const worker = new Worker(URL.createObjectURL(blob));
- worker.addEventListener('message', msg => {
- const outputCtx = document.getElementById("canvas").getContext('2d');
- outputCtx.drawImage(msg.data, 0, 0);
- document.documentElement.classList.remove("reftest-wait");
- });
- worker.postMessage(null);
-</script>
-</html>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.gaussianBlur.y-only.tentative-expected.html b/testing/web-platform/tests/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.gaussianBlur.y-only.tentative-expected.html
deleted file mode 100644
index c6d915cb07..0000000000
--- a/testing/web-platform/tests/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.gaussianBlur.y-only.tentative-expected.html
+++ /dev/null
@@ -1,15 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<title>Canvas test: 2d.filter.canvasFilterObject.gaussianBlur.y-only.tentative</title>
-<h1>2d.filter.canvasFilterObject.gaussianBlur.y-only.tentative</h1>
-<p class="desc">Test CanvasFilter() with gaussianBlur.</p>
-
-<svg xmlns="http://www.w3.org/2000/svg"
- width="100" height="100"
- color-interpolation-filters="sRGB">
- <filter id="blur" x="-50%" y="-50%" width="200%" height="200%">
- <feGaussianBlur stdDeviation="0 4" />
- </filter>
- <rect x="25" y="25" width="50" height="50"
- fill="teal" filter="url(#blur)" />
-</svg>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.gaussianBlur.y-only.tentative.html b/testing/web-platform/tests/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.gaussianBlur.y-only.tentative.html
deleted file mode 100644
index f563ad9d77..0000000000
--- a/testing/web-platform/tests/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.gaussianBlur.y-only.tentative.html
+++ /dev/null
@@ -1,23 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<link rel="match" href="2d.filter.canvasFilterObject.gaussianBlur.y-only.tentative-expected.html">
-<title>Canvas test: 2d.filter.canvasFilterObject.gaussianBlur.y-only.tentative</title>
-<h1>2d.filter.canvasFilterObject.gaussianBlur.y-only.tentative</h1>
-<p class="desc">Test CanvasFilter() with gaussianBlur.</p>
-<canvas id="canvas" width="100" height="100">
- <p class="fallback">FAIL (fallback content)</p>
-</canvas>
-<script>
- const canvas = new OffscreenCanvas(100, 100);
- const ctx = canvas.getContext('2d');
-
- ctx.fillStyle = 'teal';
- ctx.filter = new CanvasFilter({
- name: 'gaussianBlur',
- stdDeviation: [0, 4],
- });
- ctx.fillRect(25, 25, 50, 50);
-
- const outputCanvas = document.getElementById("canvas");
- outputCanvas.getContext('2d').drawImage(canvas, 0, 0);
-</script>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.gaussianBlur.y-only.tentative.w.html b/testing/web-platform/tests/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.gaussianBlur.y-only.tentative.w.html
deleted file mode 100644
index 171a41caa8..0000000000
--- a/testing/web-platform/tests/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.gaussianBlur.y-only.tentative.w.html
+++ /dev/null
@@ -1,37 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<html class="reftest-wait">
-<link rel="match" href="2d.filter.canvasFilterObject.gaussianBlur.y-only.tentative-expected.html">
-<title>Canvas test: 2d.filter.canvasFilterObject.gaussianBlur.y-only.tentative</title>
-<h1>2d.filter.canvasFilterObject.gaussianBlur.y-only.tentative</h1>
-<p class="desc">Test CanvasFilter() with gaussianBlur.</p>
-<canvas id="canvas" width="100" height="100">
- <p class="fallback">FAIL (fallback content)</p>
-</canvas>
-<script id='myWorker' type='text/worker'>
- self.onmessage = function(e) {
- const canvas = new OffscreenCanvas(100, 100);
- const ctx = canvas.getContext('2d');
-
- ctx.fillStyle = 'teal';
- ctx.filter = new CanvasFilter({
- name: 'gaussianBlur',
- stdDeviation: [0, 4],
- });
- ctx.fillRect(25, 25, 50, 50);
-
- const bitmap = canvas.transferToImageBitmap();
- self.postMessage(bitmap, bitmap);
- };
-</script>
-<script>
- const blob = new Blob([document.getElementById('myWorker').textContent]);
- const worker = new Worker(URL.createObjectURL(blob));
- worker.addEventListener('message', msg => {
- const outputCtx = document.getElementById("canvas").getContext('2d');
- outputCtx.drawImage(msg.data, 0, 0);
- document.documentElement.classList.remove("reftest-wait");
- });
- worker.postMessage(null);
-</script>
-</html>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/filters/2d.filter.layers.gaussianBlur-expected.html b/testing/web-platform/tests/html/canvas/offscreen/filters/2d.filter.layers.gaussianBlur-expected.html
new file mode 100644
index 0000000000..f24e9d0dba
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/offscreen/filters/2d.filter.layers.gaussianBlur-expected.html
@@ -0,0 +1,85 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<title>Canvas test: 2d.filter.layers.gaussianBlur</title>
+<h1 style="font-size: 20px;">2d.filter.layers.gaussianBlur</h1>
+<p class="desc">Test CanvasFilter() with gaussianBlur.</p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(5, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>x-only</div>
+ <div style="width: 100px; height: 100px; outline: 1px solid">
+ <svg xmlns="http://www.w3.org/2000/svg"
+ width="100" height="100"
+ color-interpolation-filters="sRGB">
+ <filter id="blur0" x="-50%" y="-50%" width="200%" height="200%">
+ <feGaussianBlur stdDeviation="4 0" />
+ </filter>
+ <rect x="25" y="25" width="50" height="50"
+ fill="teal" filter="url(#blur0)" />
+ </svg>
+ </div>
+</span>
+
+<span>
+ <div>mostly-x</div>
+ <div style="width: 100px; height: 100px; outline: 1px solid">
+ <svg xmlns="http://www.w3.org/2000/svg"
+ width="100" height="100"
+ color-interpolation-filters="sRGB">
+ <filter id="blur1" x="-50%" y="-50%" width="200%" height="200%">
+ <feGaussianBlur stdDeviation="4 1" />
+ </filter>
+ <rect x="25" y="25" width="50" height="50"
+ fill="teal" filter="url(#blur1)" />
+ </svg>
+ </div>
+</span>
+
+<span>
+ <div>isotropic</div>
+ <div style="width: 100px; height: 100px; outline: 1px solid">
+ <svg xmlns="http://www.w3.org/2000/svg"
+ width="100" height="100"
+ color-interpolation-filters="sRGB">
+ <filter id="blur2" x="-50%" y="-50%" width="200%" height="200%">
+ <feGaussianBlur stdDeviation="4 4" />
+ </filter>
+ <rect x="25" y="25" width="50" height="50"
+ fill="teal" filter="url(#blur2)" />
+ </svg>
+ </div>
+</span>
+
+<span>
+ <div>mostly-y</div>
+ <div style="width: 100px; height: 100px; outline: 1px solid">
+ <svg xmlns="http://www.w3.org/2000/svg"
+ width="100" height="100"
+ color-interpolation-filters="sRGB">
+ <filter id="blur3" x="-50%" y="-50%" width="200%" height="200%">
+ <feGaussianBlur stdDeviation="1 4" />
+ </filter>
+ <rect x="25" y="25" width="50" height="50"
+ fill="teal" filter="url(#blur3)" />
+ </svg>
+ </div>
+</span>
+
+<span>
+ <div>y-only</div>
+ <div style="width: 100px; height: 100px; outline: 1px solid">
+ <svg xmlns="http://www.w3.org/2000/svg"
+ width="100" height="100"
+ color-interpolation-filters="sRGB">
+ <filter id="blur4" x="-50%" y="-50%" width="200%" height="200%">
+ <feGaussianBlur stdDeviation="0 4" />
+ </filter>
+ <rect x="25" y="25" width="50" height="50"
+ fill="teal" filter="url(#blur4)" />
+ </svg>
+ </div>
+</span>
+
+</div>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/filters/2d.filter.layers.gaussianBlur.html b/testing/web-platform/tests/html/canvas/offscreen/filters/2d.filter.layers.gaussianBlur.html
new file mode 100644
index 0000000000..a51fe32008
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/offscreen/filters/2d.filter.layers.gaussianBlur.html
@@ -0,0 +1,126 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<link rel="match" href="2d.filter.layers.gaussianBlur-expected.html">
+<title>Canvas test: 2d.filter.layers.gaussianBlur</title>
+<h1 style="font-size: 20px;">2d.filter.layers.gaussianBlur</h1>
+<p class="desc">Test CanvasFilter() with gaussianBlur.</p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(5, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>x-only</div>
+ <canvas id="canvas0" width="100" height="100" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(100, 100);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'teal';
+ ctx.beginLayer({filter: {
+ name: 'gaussianBlur',
+ stdDeviation: [4, 0],
+ }});
+ ctx.fillRect(25, 25, 50, 50);
+ ctx.endLayer();
+
+ const outputCanvas = document.getElementById("canvas0");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>mostly-x</div>
+ <canvas id="canvas1" width="100" height="100" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(100, 100);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'teal';
+ ctx.beginLayer({filter: {
+ name: 'gaussianBlur',
+ stdDeviation: [4, 1],
+ }});
+ ctx.fillRect(25, 25, 50, 50);
+ ctx.endLayer();
+
+ const outputCanvas = document.getElementById("canvas1");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>isotropic</div>
+ <canvas id="canvas2" width="100" height="100" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(100, 100);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'teal';
+ ctx.beginLayer({filter: {
+ name: 'gaussianBlur',
+ stdDeviation: [4, 4],
+ }});
+ ctx.fillRect(25, 25, 50, 50);
+ ctx.endLayer();
+
+ const outputCanvas = document.getElementById("canvas2");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>mostly-y</div>
+ <canvas id="canvas3" width="100" height="100" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(100, 100);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'teal';
+ ctx.beginLayer({filter: {
+ name: 'gaussianBlur',
+ stdDeviation: [1, 4],
+ }});
+ ctx.fillRect(25, 25, 50, 50);
+ ctx.endLayer();
+
+ const outputCanvas = document.getElementById("canvas3");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>y-only</div>
+ <canvas id="canvas4" width="100" height="100" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(100, 100);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'teal';
+ ctx.beginLayer({filter: {
+ name: 'gaussianBlur',
+ stdDeviation: [0, 4],
+ }});
+ ctx.fillRect(25, 25, 50, 50);
+ ctx.endLayer();
+
+ const outputCanvas = document.getElementById("canvas4");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+</div>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/filters/2d.filter.layers.gaussianBlur.isotropic-expected.html b/testing/web-platform/tests/html/canvas/offscreen/filters/2d.filter.layers.gaussianBlur.isotropic-expected.html
deleted file mode 100644
index 4f93754862..0000000000
--- a/testing/web-platform/tests/html/canvas/offscreen/filters/2d.filter.layers.gaussianBlur.isotropic-expected.html
+++ /dev/null
@@ -1,15 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<title>Canvas test: 2d.filter.layers.gaussianBlur.isotropic</title>
-<h1>2d.filter.layers.gaussianBlur.isotropic</h1>
-<p class="desc">Test CanvasFilter() with gaussianBlur.</p>
-
-<svg xmlns="http://www.w3.org/2000/svg"
- width="100" height="100"
- color-interpolation-filters="sRGB">
- <filter id="blur" x="-50%" y="-50%" width="200%" height="200%">
- <feGaussianBlur stdDeviation="4 4" />
- </filter>
- <rect x="25" y="25" width="50" height="50"
- fill="teal" filter="url(#blur)" />
-</svg>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/filters/2d.filter.layers.gaussianBlur.isotropic.html b/testing/web-platform/tests/html/canvas/offscreen/filters/2d.filter.layers.gaussianBlur.isotropic.html
deleted file mode 100644
index 50a98df1be..0000000000
--- a/testing/web-platform/tests/html/canvas/offscreen/filters/2d.filter.layers.gaussianBlur.isotropic.html
+++ /dev/null
@@ -1,24 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<link rel="match" href="2d.filter.layers.gaussianBlur.isotropic-expected.html">
-<title>Canvas test: 2d.filter.layers.gaussianBlur.isotropic</title>
-<h1>2d.filter.layers.gaussianBlur.isotropic</h1>
-<p class="desc">Test CanvasFilter() with gaussianBlur.</p>
-<canvas id="canvas" width="100" height="100">
- <p class="fallback">FAIL (fallback content)</p>
-</canvas>
-<script>
- const canvas = new OffscreenCanvas(100, 100);
- const ctx = canvas.getContext('2d');
-
- ctx.fillStyle = 'teal';
- ctx.beginLayer({filter: {
- name: 'gaussianBlur',
- stdDeviation: [4, 4],
- }});
- ctx.fillRect(25, 25, 50, 50);
- ctx.endLayer();
-
- const outputCanvas = document.getElementById("canvas");
- outputCanvas.getContext('2d').drawImage(canvas, 0, 0);
-</script>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/filters/2d.filter.layers.gaussianBlur.isotropic.w.html b/testing/web-platform/tests/html/canvas/offscreen/filters/2d.filter.layers.gaussianBlur.isotropic.w.html
deleted file mode 100644
index a68b8e78a2..0000000000
--- a/testing/web-platform/tests/html/canvas/offscreen/filters/2d.filter.layers.gaussianBlur.isotropic.w.html
+++ /dev/null
@@ -1,38 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<html class="reftest-wait">
-<link rel="match" href="2d.filter.layers.gaussianBlur.isotropic-expected.html">
-<title>Canvas test: 2d.filter.layers.gaussianBlur.isotropic</title>
-<h1>2d.filter.layers.gaussianBlur.isotropic</h1>
-<p class="desc">Test CanvasFilter() with gaussianBlur.</p>
-<canvas id="canvas" width="100" height="100">
- <p class="fallback">FAIL (fallback content)</p>
-</canvas>
-<script id='myWorker' type='text/worker'>
- self.onmessage = function(e) {
- const canvas = new OffscreenCanvas(100, 100);
- const ctx = canvas.getContext('2d');
-
- ctx.fillStyle = 'teal';
- ctx.beginLayer({filter: {
- name: 'gaussianBlur',
- stdDeviation: [4, 4],
- }});
- ctx.fillRect(25, 25, 50, 50);
- ctx.endLayer();
-
- const bitmap = canvas.transferToImageBitmap();
- self.postMessage(bitmap, bitmap);
- };
-</script>
-<script>
- const blob = new Blob([document.getElementById('myWorker').textContent]);
- const worker = new Worker(URL.createObjectURL(blob));
- worker.addEventListener('message', msg => {
- const outputCtx = document.getElementById("canvas").getContext('2d');
- outputCtx.drawImage(msg.data, 0, 0);
- document.documentElement.classList.remove("reftest-wait");
- });
- worker.postMessage(null);
-</script>
-</html>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/filters/2d.filter.layers.gaussianBlur.mostly-x-expected.html b/testing/web-platform/tests/html/canvas/offscreen/filters/2d.filter.layers.gaussianBlur.mostly-x-expected.html
deleted file mode 100644
index 255270c192..0000000000
--- a/testing/web-platform/tests/html/canvas/offscreen/filters/2d.filter.layers.gaussianBlur.mostly-x-expected.html
+++ /dev/null
@@ -1,15 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<title>Canvas test: 2d.filter.layers.gaussianBlur.mostly-x</title>
-<h1>2d.filter.layers.gaussianBlur.mostly-x</h1>
-<p class="desc">Test CanvasFilter() with gaussianBlur.</p>
-
-<svg xmlns="http://www.w3.org/2000/svg"
- width="100" height="100"
- color-interpolation-filters="sRGB">
- <filter id="blur" x="-50%" y="-50%" width="200%" height="200%">
- <feGaussianBlur stdDeviation="4 1" />
- </filter>
- <rect x="25" y="25" width="50" height="50"
- fill="teal" filter="url(#blur)" />
-</svg>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/filters/2d.filter.layers.gaussianBlur.mostly-x.html b/testing/web-platform/tests/html/canvas/offscreen/filters/2d.filter.layers.gaussianBlur.mostly-x.html
deleted file mode 100644
index efc634796c..0000000000
--- a/testing/web-platform/tests/html/canvas/offscreen/filters/2d.filter.layers.gaussianBlur.mostly-x.html
+++ /dev/null
@@ -1,24 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<link rel="match" href="2d.filter.layers.gaussianBlur.mostly-x-expected.html">
-<title>Canvas test: 2d.filter.layers.gaussianBlur.mostly-x</title>
-<h1>2d.filter.layers.gaussianBlur.mostly-x</h1>
-<p class="desc">Test CanvasFilter() with gaussianBlur.</p>
-<canvas id="canvas" width="100" height="100">
- <p class="fallback">FAIL (fallback content)</p>
-</canvas>
-<script>
- const canvas = new OffscreenCanvas(100, 100);
- const ctx = canvas.getContext('2d');
-
- ctx.fillStyle = 'teal';
- ctx.beginLayer({filter: {
- name: 'gaussianBlur',
- stdDeviation: [4, 1],
- }});
- ctx.fillRect(25, 25, 50, 50);
- ctx.endLayer();
-
- const outputCanvas = document.getElementById("canvas");
- outputCanvas.getContext('2d').drawImage(canvas, 0, 0);
-</script>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/filters/2d.filter.layers.gaussianBlur.mostly-x.w.html b/testing/web-platform/tests/html/canvas/offscreen/filters/2d.filter.layers.gaussianBlur.mostly-x.w.html
deleted file mode 100644
index 7d20d78503..0000000000
--- a/testing/web-platform/tests/html/canvas/offscreen/filters/2d.filter.layers.gaussianBlur.mostly-x.w.html
+++ /dev/null
@@ -1,38 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<html class="reftest-wait">
-<link rel="match" href="2d.filter.layers.gaussianBlur.mostly-x-expected.html">
-<title>Canvas test: 2d.filter.layers.gaussianBlur.mostly-x</title>
-<h1>2d.filter.layers.gaussianBlur.mostly-x</h1>
-<p class="desc">Test CanvasFilter() with gaussianBlur.</p>
-<canvas id="canvas" width="100" height="100">
- <p class="fallback">FAIL (fallback content)</p>
-</canvas>
-<script id='myWorker' type='text/worker'>
- self.onmessage = function(e) {
- const canvas = new OffscreenCanvas(100, 100);
- const ctx = canvas.getContext('2d');
-
- ctx.fillStyle = 'teal';
- ctx.beginLayer({filter: {
- name: 'gaussianBlur',
- stdDeviation: [4, 1],
- }});
- ctx.fillRect(25, 25, 50, 50);
- ctx.endLayer();
-
- const bitmap = canvas.transferToImageBitmap();
- self.postMessage(bitmap, bitmap);
- };
-</script>
-<script>
- const blob = new Blob([document.getElementById('myWorker').textContent]);
- const worker = new Worker(URL.createObjectURL(blob));
- worker.addEventListener('message', msg => {
- const outputCtx = document.getElementById("canvas").getContext('2d');
- outputCtx.drawImage(msg.data, 0, 0);
- document.documentElement.classList.remove("reftest-wait");
- });
- worker.postMessage(null);
-</script>
-</html>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/filters/2d.filter.layers.gaussianBlur.mostly-y-expected.html b/testing/web-platform/tests/html/canvas/offscreen/filters/2d.filter.layers.gaussianBlur.mostly-y-expected.html
deleted file mode 100644
index 76a46b1533..0000000000
--- a/testing/web-platform/tests/html/canvas/offscreen/filters/2d.filter.layers.gaussianBlur.mostly-y-expected.html
+++ /dev/null
@@ -1,15 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<title>Canvas test: 2d.filter.layers.gaussianBlur.mostly-y</title>
-<h1>2d.filter.layers.gaussianBlur.mostly-y</h1>
-<p class="desc">Test CanvasFilter() with gaussianBlur.</p>
-
-<svg xmlns="http://www.w3.org/2000/svg"
- width="100" height="100"
- color-interpolation-filters="sRGB">
- <filter id="blur" x="-50%" y="-50%" width="200%" height="200%">
- <feGaussianBlur stdDeviation="1 4" />
- </filter>
- <rect x="25" y="25" width="50" height="50"
- fill="teal" filter="url(#blur)" />
-</svg>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/filters/2d.filter.layers.gaussianBlur.mostly-y.html b/testing/web-platform/tests/html/canvas/offscreen/filters/2d.filter.layers.gaussianBlur.mostly-y.html
deleted file mode 100644
index bdc6e66fe5..0000000000
--- a/testing/web-platform/tests/html/canvas/offscreen/filters/2d.filter.layers.gaussianBlur.mostly-y.html
+++ /dev/null
@@ -1,24 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<link rel="match" href="2d.filter.layers.gaussianBlur.mostly-y-expected.html">
-<title>Canvas test: 2d.filter.layers.gaussianBlur.mostly-y</title>
-<h1>2d.filter.layers.gaussianBlur.mostly-y</h1>
-<p class="desc">Test CanvasFilter() with gaussianBlur.</p>
-<canvas id="canvas" width="100" height="100">
- <p class="fallback">FAIL (fallback content)</p>
-</canvas>
-<script>
- const canvas = new OffscreenCanvas(100, 100);
- const ctx = canvas.getContext('2d');
-
- ctx.fillStyle = 'teal';
- ctx.beginLayer({filter: {
- name: 'gaussianBlur',
- stdDeviation: [1, 4],
- }});
- ctx.fillRect(25, 25, 50, 50);
- ctx.endLayer();
-
- const outputCanvas = document.getElementById("canvas");
- outputCanvas.getContext('2d').drawImage(canvas, 0, 0);
-</script>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/filters/2d.filter.layers.gaussianBlur.mostly-y.w.html b/testing/web-platform/tests/html/canvas/offscreen/filters/2d.filter.layers.gaussianBlur.mostly-y.w.html
deleted file mode 100644
index dfd6438b19..0000000000
--- a/testing/web-platform/tests/html/canvas/offscreen/filters/2d.filter.layers.gaussianBlur.mostly-y.w.html
+++ /dev/null
@@ -1,38 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<html class="reftest-wait">
-<link rel="match" href="2d.filter.layers.gaussianBlur.mostly-y-expected.html">
-<title>Canvas test: 2d.filter.layers.gaussianBlur.mostly-y</title>
-<h1>2d.filter.layers.gaussianBlur.mostly-y</h1>
-<p class="desc">Test CanvasFilter() with gaussianBlur.</p>
-<canvas id="canvas" width="100" height="100">
- <p class="fallback">FAIL (fallback content)</p>
-</canvas>
-<script id='myWorker' type='text/worker'>
- self.onmessage = function(e) {
- const canvas = new OffscreenCanvas(100, 100);
- const ctx = canvas.getContext('2d');
-
- ctx.fillStyle = 'teal';
- ctx.beginLayer({filter: {
- name: 'gaussianBlur',
- stdDeviation: [1, 4],
- }});
- ctx.fillRect(25, 25, 50, 50);
- ctx.endLayer();
-
- const bitmap = canvas.transferToImageBitmap();
- self.postMessage(bitmap, bitmap);
- };
-</script>
-<script>
- const blob = new Blob([document.getElementById('myWorker').textContent]);
- const worker = new Worker(URL.createObjectURL(blob));
- worker.addEventListener('message', msg => {
- const outputCtx = document.getElementById("canvas").getContext('2d');
- outputCtx.drawImage(msg.data, 0, 0);
- document.documentElement.classList.remove("reftest-wait");
- });
- worker.postMessage(null);
-</script>
-</html>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/filters/2d.filter.layers.gaussianBlur.w.html b/testing/web-platform/tests/html/canvas/offscreen/filters/2d.filter.layers.gaussianBlur.w.html
new file mode 100644
index 0000000000..10ea8baa10
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/offscreen/filters/2d.filter.layers.gaussianBlur.w.html
@@ -0,0 +1,199 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<html class="reftest-wait">
+<link rel="match" href="2d.filter.layers.gaussianBlur-expected.html">
+<title>Canvas test: 2d.filter.layers.gaussianBlur</title>
+<h1 style="font-size: 20px;">2d.filter.layers.gaussianBlur</h1>
+<p class="desc">Test CanvasFilter() with gaussianBlur.</p>
+<script>pending_tests = 5;</script>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(5, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>x-only</div>
+ <canvas id="canvas0" width="100" height="100" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script id="myWorker0" type="text/worker">
+ self.onmessage = function(e) {
+ const canvas = new OffscreenCanvas(100, 100);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'teal';
+ ctx.beginLayer({filter: {
+ name: 'gaussianBlur',
+ stdDeviation: [4, 0],
+ }});
+ ctx.fillRect(25, 25, 50, 50);
+ ctx.endLayer();
+
+ const bitmap = canvas.transferToImageBitmap();
+ self.postMessage(bitmap, bitmap);
+ };
+ </script>
+ <script type="module">
+ const blob = new Blob([document.getElementById('myWorker0').textContent]);
+ const worker = new Worker(URL.createObjectURL(blob));
+ worker.addEventListener('message', msg => {
+ const outputCanvas = document.getElementById('canvas0');
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(msg.data, 0, 0);
+ if (--pending_tests == 0) {
+ document.documentElement.classList.remove('reftest-wait');
+ }
+ });
+ worker.postMessage(null);
+ </script>
+</span>
+
+<span>
+ <div>mostly-x</div>
+ <canvas id="canvas1" width="100" height="100" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script id="myWorker1" type="text/worker">
+ self.onmessage = function(e) {
+ const canvas = new OffscreenCanvas(100, 100);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'teal';
+ ctx.beginLayer({filter: {
+ name: 'gaussianBlur',
+ stdDeviation: [4, 1],
+ }});
+ ctx.fillRect(25, 25, 50, 50);
+ ctx.endLayer();
+
+ const bitmap = canvas.transferToImageBitmap();
+ self.postMessage(bitmap, bitmap);
+ };
+ </script>
+ <script type="module">
+ const blob = new Blob([document.getElementById('myWorker1').textContent]);
+ const worker = new Worker(URL.createObjectURL(blob));
+ worker.addEventListener('message', msg => {
+ const outputCanvas = document.getElementById('canvas1');
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(msg.data, 0, 0);
+ if (--pending_tests == 0) {
+ document.documentElement.classList.remove('reftest-wait');
+ }
+ });
+ worker.postMessage(null);
+ </script>
+</span>
+
+<span>
+ <div>isotropic</div>
+ <canvas id="canvas2" width="100" height="100" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script id="myWorker2" type="text/worker">
+ self.onmessage = function(e) {
+ const canvas = new OffscreenCanvas(100, 100);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'teal';
+ ctx.beginLayer({filter: {
+ name: 'gaussianBlur',
+ stdDeviation: [4, 4],
+ }});
+ ctx.fillRect(25, 25, 50, 50);
+ ctx.endLayer();
+
+ const bitmap = canvas.transferToImageBitmap();
+ self.postMessage(bitmap, bitmap);
+ };
+ </script>
+ <script type="module">
+ const blob = new Blob([document.getElementById('myWorker2').textContent]);
+ const worker = new Worker(URL.createObjectURL(blob));
+ worker.addEventListener('message', msg => {
+ const outputCanvas = document.getElementById('canvas2');
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(msg.data, 0, 0);
+ if (--pending_tests == 0) {
+ document.documentElement.classList.remove('reftest-wait');
+ }
+ });
+ worker.postMessage(null);
+ </script>
+</span>
+
+<span>
+ <div>mostly-y</div>
+ <canvas id="canvas3" width="100" height="100" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script id="myWorker3" type="text/worker">
+ self.onmessage = function(e) {
+ const canvas = new OffscreenCanvas(100, 100);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'teal';
+ ctx.beginLayer({filter: {
+ name: 'gaussianBlur',
+ stdDeviation: [1, 4],
+ }});
+ ctx.fillRect(25, 25, 50, 50);
+ ctx.endLayer();
+
+ const bitmap = canvas.transferToImageBitmap();
+ self.postMessage(bitmap, bitmap);
+ };
+ </script>
+ <script type="module">
+ const blob = new Blob([document.getElementById('myWorker3').textContent]);
+ const worker = new Worker(URL.createObjectURL(blob));
+ worker.addEventListener('message', msg => {
+ const outputCanvas = document.getElementById('canvas3');
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(msg.data, 0, 0);
+ if (--pending_tests == 0) {
+ document.documentElement.classList.remove('reftest-wait');
+ }
+ });
+ worker.postMessage(null);
+ </script>
+</span>
+
+<span>
+ <div>y-only</div>
+ <canvas id="canvas4" width="100" height="100" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script id="myWorker4" type="text/worker">
+ self.onmessage = function(e) {
+ const canvas = new OffscreenCanvas(100, 100);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'teal';
+ ctx.beginLayer({filter: {
+ name: 'gaussianBlur',
+ stdDeviation: [0, 4],
+ }});
+ ctx.fillRect(25, 25, 50, 50);
+ ctx.endLayer();
+
+ const bitmap = canvas.transferToImageBitmap();
+ self.postMessage(bitmap, bitmap);
+ };
+ </script>
+ <script type="module">
+ const blob = new Blob([document.getElementById('myWorker4').textContent]);
+ const worker = new Worker(URL.createObjectURL(blob));
+ worker.addEventListener('message', msg => {
+ const outputCanvas = document.getElementById('canvas4');
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(msg.data, 0, 0);
+ if (--pending_tests == 0) {
+ document.documentElement.classList.remove('reftest-wait');
+ }
+ });
+ worker.postMessage(null);
+ </script>
+</span>
+
+</div>
+</html>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/filters/2d.filter.layers.gaussianBlur.x-only-expected.html b/testing/web-platform/tests/html/canvas/offscreen/filters/2d.filter.layers.gaussianBlur.x-only-expected.html
deleted file mode 100644
index 26741f9847..0000000000
--- a/testing/web-platform/tests/html/canvas/offscreen/filters/2d.filter.layers.gaussianBlur.x-only-expected.html
+++ /dev/null
@@ -1,15 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<title>Canvas test: 2d.filter.layers.gaussianBlur.x-only</title>
-<h1>2d.filter.layers.gaussianBlur.x-only</h1>
-<p class="desc">Test CanvasFilter() with gaussianBlur.</p>
-
-<svg xmlns="http://www.w3.org/2000/svg"
- width="100" height="100"
- color-interpolation-filters="sRGB">
- <filter id="blur" x="-50%" y="-50%" width="200%" height="200%">
- <feGaussianBlur stdDeviation="4 0" />
- </filter>
- <rect x="25" y="25" width="50" height="50"
- fill="teal" filter="url(#blur)" />
-</svg>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/filters/2d.filter.layers.gaussianBlur.x-only.html b/testing/web-platform/tests/html/canvas/offscreen/filters/2d.filter.layers.gaussianBlur.x-only.html
deleted file mode 100644
index 0d42acb8b5..0000000000
--- a/testing/web-platform/tests/html/canvas/offscreen/filters/2d.filter.layers.gaussianBlur.x-only.html
+++ /dev/null
@@ -1,24 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<link rel="match" href="2d.filter.layers.gaussianBlur.x-only-expected.html">
-<title>Canvas test: 2d.filter.layers.gaussianBlur.x-only</title>
-<h1>2d.filter.layers.gaussianBlur.x-only</h1>
-<p class="desc">Test CanvasFilter() with gaussianBlur.</p>
-<canvas id="canvas" width="100" height="100">
- <p class="fallback">FAIL (fallback content)</p>
-</canvas>
-<script>
- const canvas = new OffscreenCanvas(100, 100);
- const ctx = canvas.getContext('2d');
-
- ctx.fillStyle = 'teal';
- ctx.beginLayer({filter: {
- name: 'gaussianBlur',
- stdDeviation: [4, 0],
- }});
- ctx.fillRect(25, 25, 50, 50);
- ctx.endLayer();
-
- const outputCanvas = document.getElementById("canvas");
- outputCanvas.getContext('2d').drawImage(canvas, 0, 0);
-</script>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/filters/2d.filter.layers.gaussianBlur.x-only.w.html b/testing/web-platform/tests/html/canvas/offscreen/filters/2d.filter.layers.gaussianBlur.x-only.w.html
deleted file mode 100644
index b235c7ad38..0000000000
--- a/testing/web-platform/tests/html/canvas/offscreen/filters/2d.filter.layers.gaussianBlur.x-only.w.html
+++ /dev/null
@@ -1,38 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<html class="reftest-wait">
-<link rel="match" href="2d.filter.layers.gaussianBlur.x-only-expected.html">
-<title>Canvas test: 2d.filter.layers.gaussianBlur.x-only</title>
-<h1>2d.filter.layers.gaussianBlur.x-only</h1>
-<p class="desc">Test CanvasFilter() with gaussianBlur.</p>
-<canvas id="canvas" width="100" height="100">
- <p class="fallback">FAIL (fallback content)</p>
-</canvas>
-<script id='myWorker' type='text/worker'>
- self.onmessage = function(e) {
- const canvas = new OffscreenCanvas(100, 100);
- const ctx = canvas.getContext('2d');
-
- ctx.fillStyle = 'teal';
- ctx.beginLayer({filter: {
- name: 'gaussianBlur',
- stdDeviation: [4, 0],
- }});
- ctx.fillRect(25, 25, 50, 50);
- ctx.endLayer();
-
- const bitmap = canvas.transferToImageBitmap();
- self.postMessage(bitmap, bitmap);
- };
-</script>
-<script>
- const blob = new Blob([document.getElementById('myWorker').textContent]);
- const worker = new Worker(URL.createObjectURL(blob));
- worker.addEventListener('message', msg => {
- const outputCtx = document.getElementById("canvas").getContext('2d');
- outputCtx.drawImage(msg.data, 0, 0);
- document.documentElement.classList.remove("reftest-wait");
- });
- worker.postMessage(null);
-</script>
-</html>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/filters/2d.filter.layers.gaussianBlur.y-only-expected.html b/testing/web-platform/tests/html/canvas/offscreen/filters/2d.filter.layers.gaussianBlur.y-only-expected.html
deleted file mode 100644
index d00eec6b57..0000000000
--- a/testing/web-platform/tests/html/canvas/offscreen/filters/2d.filter.layers.gaussianBlur.y-only-expected.html
+++ /dev/null
@@ -1,15 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<title>Canvas test: 2d.filter.layers.gaussianBlur.y-only</title>
-<h1>2d.filter.layers.gaussianBlur.y-only</h1>
-<p class="desc">Test CanvasFilter() with gaussianBlur.</p>
-
-<svg xmlns="http://www.w3.org/2000/svg"
- width="100" height="100"
- color-interpolation-filters="sRGB">
- <filter id="blur" x="-50%" y="-50%" width="200%" height="200%">
- <feGaussianBlur stdDeviation="0 4" />
- </filter>
- <rect x="25" y="25" width="50" height="50"
- fill="teal" filter="url(#blur)" />
-</svg>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/filters/2d.filter.layers.gaussianBlur.y-only.html b/testing/web-platform/tests/html/canvas/offscreen/filters/2d.filter.layers.gaussianBlur.y-only.html
deleted file mode 100644
index c9bc85d699..0000000000
--- a/testing/web-platform/tests/html/canvas/offscreen/filters/2d.filter.layers.gaussianBlur.y-only.html
+++ /dev/null
@@ -1,24 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<link rel="match" href="2d.filter.layers.gaussianBlur.y-only-expected.html">
-<title>Canvas test: 2d.filter.layers.gaussianBlur.y-only</title>
-<h1>2d.filter.layers.gaussianBlur.y-only</h1>
-<p class="desc">Test CanvasFilter() with gaussianBlur.</p>
-<canvas id="canvas" width="100" height="100">
- <p class="fallback">FAIL (fallback content)</p>
-</canvas>
-<script>
- const canvas = new OffscreenCanvas(100, 100);
- const ctx = canvas.getContext('2d');
-
- ctx.fillStyle = 'teal';
- ctx.beginLayer({filter: {
- name: 'gaussianBlur',
- stdDeviation: [0, 4],
- }});
- ctx.fillRect(25, 25, 50, 50);
- ctx.endLayer();
-
- const outputCanvas = document.getElementById("canvas");
- outputCanvas.getContext('2d').drawImage(canvas, 0, 0);
-</script>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/filters/2d.filter.layers.gaussianBlur.y-only.w.html b/testing/web-platform/tests/html/canvas/offscreen/filters/2d.filter.layers.gaussianBlur.y-only.w.html
deleted file mode 100644
index 5deb96c255..0000000000
--- a/testing/web-platform/tests/html/canvas/offscreen/filters/2d.filter.layers.gaussianBlur.y-only.w.html
+++ /dev/null
@@ -1,38 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<html class="reftest-wait">
-<link rel="match" href="2d.filter.layers.gaussianBlur.y-only-expected.html">
-<title>Canvas test: 2d.filter.layers.gaussianBlur.y-only</title>
-<h1>2d.filter.layers.gaussianBlur.y-only</h1>
-<p class="desc">Test CanvasFilter() with gaussianBlur.</p>
-<canvas id="canvas" width="100" height="100">
- <p class="fallback">FAIL (fallback content)</p>
-</canvas>
-<script id='myWorker' type='text/worker'>
- self.onmessage = function(e) {
- const canvas = new OffscreenCanvas(100, 100);
- const ctx = canvas.getContext('2d');
-
- ctx.fillStyle = 'teal';
- ctx.beginLayer({filter: {
- name: 'gaussianBlur',
- stdDeviation: [0, 4],
- }});
- ctx.fillRect(25, 25, 50, 50);
- ctx.endLayer();
-
- const bitmap = canvas.transferToImageBitmap();
- self.postMessage(bitmap, bitmap);
- };
-</script>
-<script>
- const blob = new Blob([document.getElementById('myWorker').textContent]);
- const worker = new Worker(URL.createObjectURL(blob));
- worker.addEventListener('message', msg => {
- const outputCtx = document.getElementById("canvas").getContext('2d');
- outputCtx.drawImage(msg.data, 0, 0);
- document.documentElement.classList.remove("reftest-wait");
- });
- worker.postMessage(null);
-</script>
-</html>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.beginLayer-options.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.beginLayer-options.html
index 4fb042a1d8..354a03a134 100644
--- a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.beginLayer-options.html
+++ b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.beginLayer-options.html
@@ -10,13 +10,7 @@
<script>
-var t = async_test("Checks beginLayer works for different option parameter values");
-var t_pass = t.done.bind(t);
-var t_fail = t.step_func(function(reason) {
- throw reason;
-});
-t.step(function() {
-
+test(t => {
var canvas = new OffscreenCanvas(100, 50);
var ctx = canvas.getContext('2d');
@@ -45,7 +39,6 @@ t.step(function() {
ctx.beginLayer({filter: 1}); ctx.endLayer();
ctx.beginLayer({filter: true}); ctx.endLayer();
ctx.beginLayer({filter: false}); ctx.endLayer();
- t.done();
-});
+}, "Checks beginLayer works for different option parameter values");
</script>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.beginLayer-options.worker.js b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.beginLayer-options.worker.js
index cafbc83f3e..492ac3fcea 100644
--- a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.beginLayer-options.worker.js
+++ b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.beginLayer-options.worker.js
@@ -6,13 +6,7 @@
importScripts("/resources/testharness.js");
importScripts("/html/canvas/resources/canvas-tests.js");
-var t = async_test("Checks beginLayer works for different option parameter values");
-var t_pass = t.done.bind(t);
-var t_fail = t.step_func(function(reason) {
- throw reason;
-});
-t.step(function() {
-
+test(t => {
var canvas = new OffscreenCanvas(100, 50);
var ctx = canvas.getContext('2d');
@@ -41,6 +35,5 @@ t.step(function() {
ctx.beginLayer({filter: 1}); ctx.endLayer();
ctx.beginLayer({filter: true}); ctx.endLayer();
ctx.beginLayer({filter: false}); ctx.endLayer();
- t.done();
-});
+}, "Checks beginLayer works for different option parameter values");
done();
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.ctm.getTransform.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.ctm.getTransform.html
index b2306d95ac..919de40d2e 100644
--- a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.ctm.getTransform.html
+++ b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.ctm.getTransform.html
@@ -10,13 +10,7 @@
<script>
-var t = async_test("Tests getTransform inside layers.");
-var t_pass = t.done.bind(t);
-var t_fail = t.step_func(function(reason) {
- throw reason;
-});
-t.step(function() {
-
+test(t => {
var canvas = new OffscreenCanvas(100, 50);
var ctx = canvas.getContext('2d');
@@ -26,7 +20,6 @@ t.step(function() {
const m = ctx.getTransform();
assert_array_equals([m.a, m.b, m.c, m.d, m.e, m.f], [2, 0, 0, 3, 10, 20]);
ctx.endLayer();
- t.done();
-});
+}, "Tests getTransform inside layers.");
</script>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.ctm.getTransform.worker.js b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.ctm.getTransform.worker.js
index 54b1fee5d0..2d6e6ef8a2 100644
--- a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.ctm.getTransform.worker.js
+++ b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.ctm.getTransform.worker.js
@@ -6,13 +6,7 @@
importScripts("/resources/testharness.js");
importScripts("/html/canvas/resources/canvas-tests.js");
-var t = async_test("Tests getTransform inside layers.");
-var t_pass = t.done.bind(t);
-var t_fail = t.step_func(function(reason) {
- throw reason;
-});
-t.step(function() {
-
+test(t => {
var canvas = new OffscreenCanvas(100, 50);
var ctx = canvas.getContext('2d');
@@ -22,6 +16,5 @@ t.step(function() {
const m = ctx.getTransform();
assert_array_equals([m.a, m.b, m.c, m.d, m.e, m.f], [2, 0, 0, 3, 10, 20]);
ctx.endLayer();
- t.done();
-});
+}, "Tests getTransform inside layers.");
done();
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.exceptions-are-no-op.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.exceptions-are-no-op.html
index a047c539cf..29b316b256 100644
--- a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.exceptions-are-no-op.html
+++ b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.exceptions-are-no-op.html
@@ -10,13 +10,7 @@
<script>
-var t = async_test("Checks that the context state is left unchanged if beginLayer throws.");
-var t_pass = t.done.bind(t);
-var t_fail = t.step_func(function(reason) {
- throw reason;
-});
-t.step(function() {
-
+test(t => {
var canvas = new OffscreenCanvas(100, 50);
var ctx = canvas.getContext('2d');
@@ -26,7 +20,6 @@ t.step(function() {
values: 'foo'}}));
// `beginLayer` shouldn't have opened the layer, so `endLayer` should throw.
assert_throws_dom("InvalidStateError", () => ctx.endLayer());
- t.done();
-});
+}, "Checks that the context state is left unchanged if beginLayer throws.");
</script>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.exceptions-are-no-op.worker.js b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.exceptions-are-no-op.worker.js
index bd1e376084..6e253b26d5 100644
--- a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.exceptions-are-no-op.worker.js
+++ b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.exceptions-are-no-op.worker.js
@@ -6,13 +6,7 @@
importScripts("/resources/testharness.js");
importScripts("/html/canvas/resources/canvas-tests.js");
-var t = async_test("Checks that the context state is left unchanged if beginLayer throws.");
-var t_pass = t.done.bind(t);
-var t_fail = t.step_func(function(reason) {
- throw reason;
-});
-t.step(function() {
-
+test(t => {
var canvas = new OffscreenCanvas(100, 50);
var ctx = canvas.getContext('2d');
@@ -22,6 +16,5 @@ t.step(function() {
values: 'foo'}}));
// `beginLayer` shouldn't have opened the layer, so `endLayer` should throw.
assert_throws_dom("InvalidStateError", () => ctx.endLayer());
- t.done();
-});
+}, "Checks that the context state is left unchanged if beginLayer throws.");
done();
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.alpha-expected.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.alpha-expected.html
deleted file mode 100644
index 0666e3098a..0000000000
--- a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.alpha-expected.html
+++ /dev/null
@@ -1,31 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<title>Canvas test: 2d.layer.global-states.alpha</title>
-<h1>2d.layer.global-states.alpha</h1>
-<p class="desc">Checks that layers correctly use global render states.</p>
-<canvas id="canvas" width="200" height="200">
- <p class="fallback">FAIL (fallback content)</p>
-</canvas>
-<script>
- const canvas = document.getElementById("canvas");
- const ctx = canvas.getContext('2d');
-
- ctx.fillStyle = 'rgba(0, 0, 255, 1)';
-
- var circle = new Path2D();
- circle.arc(90, 90, 45, 0, 2 * Math.PI);
- ctx.fill(circle);
-
- ctx.globalAlpha = 0.6;
-
- canvas2 = document.createElement("canvas");
- ctx2 = canvas2.getContext("2d");
-
- ctx2.globalCompositeOperation = 'screen';
- ctx2.fillStyle = 'rgba(225, 0, 0, 1)';
- ctx2.fillRect(50, 50, 75, 50);
- ctx2.fillStyle = 'rgba(0, 255, 0, 1)';
- ctx2.fillRect(70, 70, 75, 50);
-
- ctx.drawImage(canvas2, 0, 0);
-</script>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.alpha.blending-expected.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.alpha.blending-expected.html
deleted file mode 100644
index 8a45027588..0000000000
--- a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.alpha.blending-expected.html
+++ /dev/null
@@ -1,32 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<title>Canvas test: 2d.layer.global-states.alpha.blending</title>
-<h1>2d.layer.global-states.alpha.blending</h1>
-<p class="desc">Checks that layers correctly use global render states.</p>
-<canvas id="canvas" width="200" height="200">
- <p class="fallback">FAIL (fallback content)</p>
-</canvas>
-<script>
- const canvas = document.getElementById("canvas");
- const ctx = canvas.getContext('2d');
-
- ctx.fillStyle = 'rgba(0, 0, 255, 1)';
-
- var circle = new Path2D();
- circle.arc(90, 90, 45, 0, 2 * Math.PI);
- ctx.fill(circle);
-
- ctx.globalAlpha = 0.6;
- ctx.globalCompositeOperation = 'multiply';
-
- canvas2 = document.createElement("canvas");
- ctx2 = canvas2.getContext("2d");
-
- ctx2.globalCompositeOperation = 'screen';
- ctx2.fillStyle = 'rgba(225, 0, 0, 1)';
- ctx2.fillRect(50, 50, 75, 50);
- ctx2.fillStyle = 'rgba(0, 255, 0, 1)';
- ctx2.fillRect(70, 70, 75, 50);
-
- ctx.drawImage(canvas2, 0, 0);
-</script>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.alpha.blending.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.alpha.blending.html
deleted file mode 100644
index 71414b4b37..0000000000
--- a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.alpha.blending.html
+++ /dev/null
@@ -1,38 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<link rel="match" href="2d.layer.global-states.alpha.blending-expected.html">
-<title>Canvas test: 2d.layer.global-states.alpha.blending</title>
-<h1>2d.layer.global-states.alpha.blending</h1>
-<p class="desc">Checks that layers correctly use global render states.</p>
-<canvas id="canvas" width="200" height="200">
- <p class="fallback">FAIL (fallback content)</p>
-</canvas>
-<script>
- const canvas = new OffscreenCanvas(200, 200);
- const ctx = canvas.getContext('2d');
-
- ctx.fillStyle = 'rgba(0, 0, 255, 1)';
-
- var circle = new Path2D();
- circle.arc(90, 90, 45, 0, 2 * Math.PI);
- ctx.fill(circle);
-
- ctx.globalAlpha = 0.6;
- ctx.globalCompositeOperation = 'multiply';
-
- ctx.beginLayer();
-
- // Enable compositing in the layer to validate that draw calls in the layer
- // 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(0, 255, 0, 1)';
- ctx.fillRect(70, 70, 75, 50);
-
- ctx.endLayer();
-
- const outputCanvas = document.getElementById("canvas");
- outputCanvas.getContext('2d').drawImage(canvas, 0, 0);
-</script>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.alpha.blending.shadow-expected.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.alpha.blending.shadow-expected.html
deleted file mode 100644
index f7b633b35f..0000000000
--- a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.alpha.blending.shadow-expected.html
+++ /dev/null
@@ -1,36 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<title>Canvas test: 2d.layer.global-states.alpha.blending.shadow</title>
-<h1>2d.layer.global-states.alpha.blending.shadow</h1>
-<p class="desc">Checks that layers correctly use global render states.</p>
-<canvas id="canvas" width="200" height="200">
- <p class="fallback">FAIL (fallback content)</p>
-</canvas>
-<script>
- const canvas = document.getElementById("canvas");
- const ctx = canvas.getContext('2d');
-
- ctx.fillStyle = 'rgba(0, 0, 255, 1)';
-
- var circle = new Path2D();
- circle.arc(90, 90, 45, 0, 2 * Math.PI);
- ctx.fill(circle);
-
- ctx.globalAlpha = 0.6;
- ctx.globalCompositeOperation = 'multiply';
- ctx.shadowOffsetX = -10;
- ctx.shadowOffsetY = 10;
- ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
- ctx.shadowBlur = 3;
-
- canvas2 = document.createElement("canvas");
- ctx2 = canvas2.getContext("2d");
-
- ctx2.globalCompositeOperation = 'screen';
- ctx2.fillStyle = 'rgba(225, 0, 0, 1)';
- ctx2.fillRect(50, 50, 75, 50);
- ctx2.fillStyle = 'rgba(0, 255, 0, 1)';
- ctx2.fillRect(70, 70, 75, 50);
-
- ctx.drawImage(canvas2, 0, 0);
-</script>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.alpha.blending.shadow.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.alpha.blending.shadow.html
deleted file mode 100644
index ed2d2d70af..0000000000
--- a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.alpha.blending.shadow.html
+++ /dev/null
@@ -1,42 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<link rel="match" href="2d.layer.global-states.alpha.blending.shadow-expected.html">
-<title>Canvas test: 2d.layer.global-states.alpha.blending.shadow</title>
-<h1>2d.layer.global-states.alpha.blending.shadow</h1>
-<p class="desc">Checks that layers correctly use global render states.</p>
-<canvas id="canvas" width="200" height="200">
- <p class="fallback">FAIL (fallback content)</p>
-</canvas>
-<script>
- const canvas = new OffscreenCanvas(200, 200);
- const ctx = canvas.getContext('2d');
-
- ctx.fillStyle = 'rgba(0, 0, 255, 1)';
-
- var circle = new Path2D();
- circle.arc(90, 90, 45, 0, 2 * Math.PI);
- ctx.fill(circle);
-
- ctx.globalAlpha = 0.6;
- ctx.globalCompositeOperation = 'multiply';
- ctx.shadowOffsetX = -10;
- ctx.shadowOffsetY = 10;
- ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
- ctx.shadowBlur = 3;
-
- ctx.beginLayer();
-
- // Enable compositing in the layer to validate that draw calls in the layer
- // 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(0, 255, 0, 1)';
- ctx.fillRect(70, 70, 75, 50);
-
- ctx.endLayer();
-
- const outputCanvas = document.getElementById("canvas");
- outputCanvas.getContext('2d').drawImage(canvas, 0, 0);
-</script>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.alpha.blending.shadow.w.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.alpha.blending.shadow.w.html
deleted file mode 100644
index 1ff3ad8385..0000000000
--- a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.alpha.blending.shadow.w.html
+++ /dev/null
@@ -1,56 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<html class="reftest-wait">
-<link rel="match" href="2d.layer.global-states.alpha.blending.shadow-expected.html">
-<title>Canvas test: 2d.layer.global-states.alpha.blending.shadow</title>
-<h1>2d.layer.global-states.alpha.blending.shadow</h1>
-<p class="desc">Checks that layers correctly use global render states.</p>
-<canvas id="canvas" width="200" height="200">
- <p class="fallback">FAIL (fallback content)</p>
-</canvas>
-<script id='myWorker' type='text/worker'>
- self.onmessage = function(e) {
- const canvas = new OffscreenCanvas(200, 200);
- const ctx = canvas.getContext('2d');
-
- ctx.fillStyle = 'rgba(0, 0, 255, 1)';
-
- var circle = new Path2D();
- circle.arc(90, 90, 45, 0, 2 * Math.PI);
- ctx.fill(circle);
-
- ctx.globalAlpha = 0.6;
- ctx.globalCompositeOperation = 'multiply';
- ctx.shadowOffsetX = -10;
- ctx.shadowOffsetY = 10;
- ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
- ctx.shadowBlur = 3;
-
- ctx.beginLayer();
-
- // Enable compositing in the layer to validate that draw calls in the layer
- // 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(0, 255, 0, 1)';
- ctx.fillRect(70, 70, 75, 50);
-
- ctx.endLayer();
-
- const bitmap = canvas.transferToImageBitmap();
- self.postMessage(bitmap, bitmap);
- };
-</script>
-<script>
- const blob = new Blob([document.getElementById('myWorker').textContent]);
- const worker = new Worker(URL.createObjectURL(blob));
- worker.addEventListener('message', msg => {
- const outputCtx = document.getElementById("canvas").getContext('2d');
- outputCtx.drawImage(msg.data, 0, 0);
- document.documentElement.classList.remove("reftest-wait");
- });
- worker.postMessage(null);
-</script>
-</html>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.alpha.blending.w.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.alpha.blending.w.html
deleted file mode 100644
index 618480c813..0000000000
--- a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.alpha.blending.w.html
+++ /dev/null
@@ -1,52 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<html class="reftest-wait">
-<link rel="match" href="2d.layer.global-states.alpha.blending-expected.html">
-<title>Canvas test: 2d.layer.global-states.alpha.blending</title>
-<h1>2d.layer.global-states.alpha.blending</h1>
-<p class="desc">Checks that layers correctly use global render states.</p>
-<canvas id="canvas" width="200" height="200">
- <p class="fallback">FAIL (fallback content)</p>
-</canvas>
-<script id='myWorker' type='text/worker'>
- self.onmessage = function(e) {
- const canvas = new OffscreenCanvas(200, 200);
- const ctx = canvas.getContext('2d');
-
- ctx.fillStyle = 'rgba(0, 0, 255, 1)';
-
- var circle = new Path2D();
- circle.arc(90, 90, 45, 0, 2 * Math.PI);
- ctx.fill(circle);
-
- ctx.globalAlpha = 0.6;
- ctx.globalCompositeOperation = 'multiply';
-
- ctx.beginLayer();
-
- // Enable compositing in the layer to validate that draw calls in the layer
- // 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(0, 255, 0, 1)';
- ctx.fillRect(70, 70, 75, 50);
-
- ctx.endLayer();
-
- const bitmap = canvas.transferToImageBitmap();
- self.postMessage(bitmap, bitmap);
- };
-</script>
-<script>
- const blob = new Blob([document.getElementById('myWorker').textContent]);
- const worker = new Worker(URL.createObjectURL(blob));
- worker.addEventListener('message', msg => {
- const outputCtx = document.getElementById("canvas").getContext('2d');
- outputCtx.drawImage(msg.data, 0, 0);
- document.documentElement.classList.remove("reftest-wait");
- });
- worker.postMessage(null);
-</script>
-</html>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.alpha.composite-expected.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.alpha.composite-expected.html
deleted file mode 100644
index 951049e638..0000000000
--- a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.alpha.composite-expected.html
+++ /dev/null
@@ -1,32 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<title>Canvas test: 2d.layer.global-states.alpha.composite</title>
-<h1>2d.layer.global-states.alpha.composite</h1>
-<p class="desc">Checks that layers correctly use global render states.</p>
-<canvas id="canvas" width="200" height="200">
- <p class="fallback">FAIL (fallback content)</p>
-</canvas>
-<script>
- const canvas = document.getElementById("canvas");
- const ctx = canvas.getContext('2d');
-
- ctx.fillStyle = 'rgba(0, 0, 255, 1)';
-
- var circle = new Path2D();
- circle.arc(90, 90, 45, 0, 2 * Math.PI);
- ctx.fill(circle);
-
- ctx.globalAlpha = 0.6;
- ctx.globalCompositeOperation = 'source-in';
-
- canvas2 = document.createElement("canvas");
- ctx2 = canvas2.getContext("2d");
-
- ctx2.globalCompositeOperation = 'screen';
- ctx2.fillStyle = 'rgba(225, 0, 0, 1)';
- ctx2.fillRect(50, 50, 75, 50);
- ctx2.fillStyle = 'rgba(0, 255, 0, 1)';
- ctx2.fillRect(70, 70, 75, 50);
-
- ctx.drawImage(canvas2, 0, 0);
-</script>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.alpha.composite.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.alpha.composite.html
deleted file mode 100644
index 94fed5752d..0000000000
--- a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.alpha.composite.html
+++ /dev/null
@@ -1,38 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<link rel="match" href="2d.layer.global-states.alpha.composite-expected.html">
-<title>Canvas test: 2d.layer.global-states.alpha.composite</title>
-<h1>2d.layer.global-states.alpha.composite</h1>
-<p class="desc">Checks that layers correctly use global render states.</p>
-<canvas id="canvas" width="200" height="200">
- <p class="fallback">FAIL (fallback content)</p>
-</canvas>
-<script>
- const canvas = new OffscreenCanvas(200, 200);
- const ctx = canvas.getContext('2d');
-
- ctx.fillStyle = 'rgba(0, 0, 255, 1)';
-
- var circle = new Path2D();
- circle.arc(90, 90, 45, 0, 2 * Math.PI);
- ctx.fill(circle);
-
- ctx.globalAlpha = 0.6;
- ctx.globalCompositeOperation = 'source-in';
-
- ctx.beginLayer();
-
- // Enable compositing in the layer to validate that draw calls in the layer
- // 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(0, 255, 0, 1)';
- ctx.fillRect(70, 70, 75, 50);
-
- ctx.endLayer();
-
- const outputCanvas = document.getElementById("canvas");
- outputCanvas.getContext('2d').drawImage(canvas, 0, 0);
-</script>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.alpha.composite.shadow-expected.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.alpha.composite.shadow-expected.html
deleted file mode 100644
index 0ae93871f5..0000000000
--- a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.alpha.composite.shadow-expected.html
+++ /dev/null
@@ -1,36 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<title>Canvas test: 2d.layer.global-states.alpha.composite.shadow</title>
-<h1>2d.layer.global-states.alpha.composite.shadow</h1>
-<p class="desc">Checks that layers correctly use global render states.</p>
-<canvas id="canvas" width="200" height="200">
- <p class="fallback">FAIL (fallback content)</p>
-</canvas>
-<script>
- const canvas = document.getElementById("canvas");
- const ctx = canvas.getContext('2d');
-
- ctx.fillStyle = 'rgba(0, 0, 255, 1)';
-
- var circle = new Path2D();
- circle.arc(90, 90, 45, 0, 2 * Math.PI);
- ctx.fill(circle);
-
- 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;
-
- canvas2 = document.createElement("canvas");
- ctx2 = canvas2.getContext("2d");
-
- ctx2.globalCompositeOperation = 'screen';
- ctx2.fillStyle = 'rgba(225, 0, 0, 1)';
- ctx2.fillRect(50, 50, 75, 50);
- ctx2.fillStyle = 'rgba(0, 255, 0, 1)';
- ctx2.fillRect(70, 70, 75, 50);
-
- ctx.drawImage(canvas2, 0, 0);
-</script>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.alpha.composite.shadow.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.alpha.composite.shadow.html
deleted file mode 100644
index eb579cdcce..0000000000
--- a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.alpha.composite.shadow.html
+++ /dev/null
@@ -1,42 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<link rel="match" href="2d.layer.global-states.alpha.composite.shadow-expected.html">
-<title>Canvas test: 2d.layer.global-states.alpha.composite.shadow</title>
-<h1>2d.layer.global-states.alpha.composite.shadow</h1>
-<p class="desc">Checks that layers correctly use global render states.</p>
-<canvas id="canvas" width="200" height="200">
- <p class="fallback">FAIL (fallback content)</p>
-</canvas>
-<script>
- const canvas = new OffscreenCanvas(200, 200);
- const ctx = canvas.getContext('2d');
-
- ctx.fillStyle = 'rgba(0, 0, 255, 1)';
-
- var circle = new Path2D();
- circle.arc(90, 90, 45, 0, 2 * Math.PI);
- ctx.fill(circle);
-
- 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;
-
- ctx.beginLayer();
-
- // Enable compositing in the layer to validate that draw calls in the layer
- // 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(0, 255, 0, 1)';
- ctx.fillRect(70, 70, 75, 50);
-
- ctx.endLayer();
-
- const outputCanvas = document.getElementById("canvas");
- outputCanvas.getContext('2d').drawImage(canvas, 0, 0);
-</script>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.alpha.composite.shadow.w.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.alpha.composite.shadow.w.html
deleted file mode 100644
index 60e36f4b97..0000000000
--- a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.alpha.composite.shadow.w.html
+++ /dev/null
@@ -1,56 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<html class="reftest-wait">
-<link rel="match" href="2d.layer.global-states.alpha.composite.shadow-expected.html">
-<title>Canvas test: 2d.layer.global-states.alpha.composite.shadow</title>
-<h1>2d.layer.global-states.alpha.composite.shadow</h1>
-<p class="desc">Checks that layers correctly use global render states.</p>
-<canvas id="canvas" width="200" height="200">
- <p class="fallback">FAIL (fallback content)</p>
-</canvas>
-<script id='myWorker' type='text/worker'>
- self.onmessage = function(e) {
- const canvas = new OffscreenCanvas(200, 200);
- const ctx = canvas.getContext('2d');
-
- ctx.fillStyle = 'rgba(0, 0, 255, 1)';
-
- var circle = new Path2D();
- circle.arc(90, 90, 45, 0, 2 * Math.PI);
- ctx.fill(circle);
-
- 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;
-
- ctx.beginLayer();
-
- // Enable compositing in the layer to validate that draw calls in the layer
- // 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(0, 255, 0, 1)';
- ctx.fillRect(70, 70, 75, 50);
-
- ctx.endLayer();
-
- const bitmap = canvas.transferToImageBitmap();
- self.postMessage(bitmap, bitmap);
- };
-</script>
-<script>
- const blob = new Blob([document.getElementById('myWorker').textContent]);
- const worker = new Worker(URL.createObjectURL(blob));
- worker.addEventListener('message', msg => {
- const outputCtx = document.getElementById("canvas").getContext('2d');
- outputCtx.drawImage(msg.data, 0, 0);
- document.documentElement.classList.remove("reftest-wait");
- });
- worker.postMessage(null);
-</script>
-</html>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.alpha.composite.w.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.alpha.composite.w.html
deleted file mode 100644
index d7d2b7a21e..0000000000
--- a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.alpha.composite.w.html
+++ /dev/null
@@ -1,52 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<html class="reftest-wait">
-<link rel="match" href="2d.layer.global-states.alpha.composite-expected.html">
-<title>Canvas test: 2d.layer.global-states.alpha.composite</title>
-<h1>2d.layer.global-states.alpha.composite</h1>
-<p class="desc">Checks that layers correctly use global render states.</p>
-<canvas id="canvas" width="200" height="200">
- <p class="fallback">FAIL (fallback content)</p>
-</canvas>
-<script id='myWorker' type='text/worker'>
- self.onmessage = function(e) {
- const canvas = new OffscreenCanvas(200, 200);
- const ctx = canvas.getContext('2d');
-
- ctx.fillStyle = 'rgba(0, 0, 255, 1)';
-
- var circle = new Path2D();
- circle.arc(90, 90, 45, 0, 2 * Math.PI);
- ctx.fill(circle);
-
- ctx.globalAlpha = 0.6;
- ctx.globalCompositeOperation = 'source-in';
-
- ctx.beginLayer();
-
- // Enable compositing in the layer to validate that draw calls in the layer
- // 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(0, 255, 0, 1)';
- ctx.fillRect(70, 70, 75, 50);
-
- ctx.endLayer();
-
- const bitmap = canvas.transferToImageBitmap();
- self.postMessage(bitmap, bitmap);
- };
-</script>
-<script>
- const blob = new Blob([document.getElementById('myWorker').textContent]);
- const worker = new Worker(URL.createObjectURL(blob));
- worker.addEventListener('message', msg => {
- const outputCtx = document.getElementById("canvas").getContext('2d');
- outputCtx.drawImage(msg.data, 0, 0);
- document.documentElement.classList.remove("reftest-wait");
- });
- worker.postMessage(null);
-</script>
-</html>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.alpha.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.alpha.html
deleted file mode 100644
index 63a264e681..0000000000
--- a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.alpha.html
+++ /dev/null
@@ -1,37 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<link rel="match" href="2d.layer.global-states.alpha-expected.html">
-<title>Canvas test: 2d.layer.global-states.alpha</title>
-<h1>2d.layer.global-states.alpha</h1>
-<p class="desc">Checks that layers correctly use global render states.</p>
-<canvas id="canvas" width="200" height="200">
- <p class="fallback">FAIL (fallback content)</p>
-</canvas>
-<script>
- const canvas = new OffscreenCanvas(200, 200);
- const ctx = canvas.getContext('2d');
-
- ctx.fillStyle = 'rgba(0, 0, 255, 1)';
-
- var circle = new Path2D();
- circle.arc(90, 90, 45, 0, 2 * Math.PI);
- ctx.fill(circle);
-
- ctx.globalAlpha = 0.6;
-
- ctx.beginLayer();
-
- // Enable compositing in the layer to validate that draw calls in the layer
- // 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(0, 255, 0, 1)';
- ctx.fillRect(70, 70, 75, 50);
-
- ctx.endLayer();
-
- const outputCanvas = document.getElementById("canvas");
- outputCanvas.getContext('2d').drawImage(canvas, 0, 0);
-</script>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.alpha.shadow-expected.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.alpha.shadow-expected.html
deleted file mode 100644
index 6f764c5001..0000000000
--- a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.alpha.shadow-expected.html
+++ /dev/null
@@ -1,35 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<title>Canvas test: 2d.layer.global-states.alpha.shadow</title>
-<h1>2d.layer.global-states.alpha.shadow</h1>
-<p class="desc">Checks that layers correctly use global render states.</p>
-<canvas id="canvas" width="200" height="200">
- <p class="fallback">FAIL (fallback content)</p>
-</canvas>
-<script>
- const canvas = document.getElementById("canvas");
- const ctx = canvas.getContext('2d');
-
- ctx.fillStyle = 'rgba(0, 0, 255, 1)';
-
- var circle = new Path2D();
- circle.arc(90, 90, 45, 0, 2 * Math.PI);
- ctx.fill(circle);
-
- ctx.globalAlpha = 0.5;
- ctx.shadowOffsetX = -10;
- ctx.shadowOffsetY = 10;
- ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
- ctx.shadowBlur = 3;
-
- canvas2 = document.createElement("canvas");
- ctx2 = canvas2.getContext("2d");
-
- ctx2.globalCompositeOperation = 'screen';
- ctx2.fillStyle = 'rgba(225, 0, 0, 1)';
- ctx2.fillRect(50, 50, 75, 50);
- ctx2.fillStyle = 'rgba(0, 255, 0, 1)';
- ctx2.fillRect(70, 70, 75, 50);
-
- ctx.drawImage(canvas2, 0, 0);
-</script>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.alpha.shadow.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.alpha.shadow.html
deleted file mode 100644
index 65a66c977d..0000000000
--- a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.alpha.shadow.html
+++ /dev/null
@@ -1,41 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<link rel="match" href="2d.layer.global-states.alpha.shadow-expected.html">
-<title>Canvas test: 2d.layer.global-states.alpha.shadow</title>
-<h1>2d.layer.global-states.alpha.shadow</h1>
-<p class="desc">Checks that layers correctly use global render states.</p>
-<canvas id="canvas" width="200" height="200">
- <p class="fallback">FAIL (fallback content)</p>
-</canvas>
-<script>
- const canvas = new OffscreenCanvas(200, 200);
- const ctx = canvas.getContext('2d');
-
- ctx.fillStyle = 'rgba(0, 0, 255, 1)';
-
- var circle = new Path2D();
- circle.arc(90, 90, 45, 0, 2 * Math.PI);
- ctx.fill(circle);
-
- ctx.globalAlpha = 0.5;
- ctx.shadowOffsetX = -10;
- ctx.shadowOffsetY = 10;
- ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
- ctx.shadowBlur = 3;
-
- ctx.beginLayer();
-
- // Enable compositing in the layer to validate that draw calls in the layer
- // 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(0, 255, 0, 1)';
- ctx.fillRect(70, 70, 75, 50);
-
- ctx.endLayer();
-
- const outputCanvas = document.getElementById("canvas");
- outputCanvas.getContext('2d').drawImage(canvas, 0, 0);
-</script>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.alpha.shadow.w.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.alpha.shadow.w.html
deleted file mode 100644
index f404601e3d..0000000000
--- a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.alpha.shadow.w.html
+++ /dev/null
@@ -1,55 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<html class="reftest-wait">
-<link rel="match" href="2d.layer.global-states.alpha.shadow-expected.html">
-<title>Canvas test: 2d.layer.global-states.alpha.shadow</title>
-<h1>2d.layer.global-states.alpha.shadow</h1>
-<p class="desc">Checks that layers correctly use global render states.</p>
-<canvas id="canvas" width="200" height="200">
- <p class="fallback">FAIL (fallback content)</p>
-</canvas>
-<script id='myWorker' type='text/worker'>
- self.onmessage = function(e) {
- const canvas = new OffscreenCanvas(200, 200);
- const ctx = canvas.getContext('2d');
-
- ctx.fillStyle = 'rgba(0, 0, 255, 1)';
-
- var circle = new Path2D();
- circle.arc(90, 90, 45, 0, 2 * Math.PI);
- ctx.fill(circle);
-
- ctx.globalAlpha = 0.5;
- ctx.shadowOffsetX = -10;
- ctx.shadowOffsetY = 10;
- ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
- ctx.shadowBlur = 3;
-
- ctx.beginLayer();
-
- // Enable compositing in the layer to validate that draw calls in the layer
- // 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(0, 255, 0, 1)';
- ctx.fillRect(70, 70, 75, 50);
-
- ctx.endLayer();
-
- const bitmap = canvas.transferToImageBitmap();
- self.postMessage(bitmap, bitmap);
- };
-</script>
-<script>
- const blob = new Blob([document.getElementById('myWorker').textContent]);
- const worker = new Worker(URL.createObjectURL(blob));
- worker.addEventListener('message', msg => {
- const outputCtx = document.getElementById("canvas").getContext('2d');
- outputCtx.drawImage(msg.data, 0, 0);
- document.documentElement.classList.remove("reftest-wait");
- });
- worker.postMessage(null);
-</script>
-</html>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.alpha.w.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.alpha.w.html
deleted file mode 100644
index 694f31e208..0000000000
--- a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.alpha.w.html
+++ /dev/null
@@ -1,51 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<html class="reftest-wait">
-<link rel="match" href="2d.layer.global-states.alpha-expected.html">
-<title>Canvas test: 2d.layer.global-states.alpha</title>
-<h1>2d.layer.global-states.alpha</h1>
-<p class="desc">Checks that layers correctly use global render states.</p>
-<canvas id="canvas" width="200" height="200">
- <p class="fallback">FAIL (fallback content)</p>
-</canvas>
-<script id='myWorker' type='text/worker'>
- self.onmessage = function(e) {
- const canvas = new OffscreenCanvas(200, 200);
- const ctx = canvas.getContext('2d');
-
- ctx.fillStyle = 'rgba(0, 0, 255, 1)';
-
- var circle = new Path2D();
- circle.arc(90, 90, 45, 0, 2 * Math.PI);
- ctx.fill(circle);
-
- ctx.globalAlpha = 0.6;
-
- ctx.beginLayer();
-
- // Enable compositing in the layer to validate that draw calls in the layer
- // 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(0, 255, 0, 1)';
- ctx.fillRect(70, 70, 75, 50);
-
- ctx.endLayer();
-
- const bitmap = canvas.transferToImageBitmap();
- self.postMessage(bitmap, bitmap);
- };
-</script>
-<script>
- const blob = new Blob([document.getElementById('myWorker').textContent]);
- const worker = new Worker(URL.createObjectURL(blob));
- worker.addEventListener('message', msg => {
- const outputCtx = document.getElementById("canvas").getContext('2d');
- outputCtx.drawImage(msg.data, 0, 0);
- document.documentElement.classList.remove("reftest-wait");
- });
- worker.postMessage(null);
-</script>
-</html>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.blending-expected.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.blending-expected.html
deleted file mode 100644
index 33fdf46a28..0000000000
--- a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.blending-expected.html
+++ /dev/null
@@ -1,31 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<title>Canvas test: 2d.layer.global-states.blending</title>
-<h1>2d.layer.global-states.blending</h1>
-<p class="desc">Checks that layers correctly use global render states.</p>
-<canvas id="canvas" width="200" height="200">
- <p class="fallback">FAIL (fallback content)</p>
-</canvas>
-<script>
- const canvas = document.getElementById("canvas");
- const ctx = canvas.getContext('2d');
-
- ctx.fillStyle = 'rgba(0, 0, 255, 1)';
-
- var circle = new Path2D();
- circle.arc(90, 90, 45, 0, 2 * Math.PI);
- ctx.fill(circle);
-
- ctx.globalCompositeOperation = 'multiply';
-
- canvas2 = document.createElement("canvas");
- ctx2 = canvas2.getContext("2d");
-
- ctx2.globalCompositeOperation = 'screen';
- ctx2.fillStyle = 'rgba(225, 0, 0, 1)';
- ctx2.fillRect(50, 50, 75, 50);
- ctx2.fillStyle = 'rgba(0, 255, 0, 1)';
- ctx2.fillRect(70, 70, 75, 50);
-
- ctx.drawImage(canvas2, 0, 0);
-</script>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.blending.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.blending.html
deleted file mode 100644
index 6a36bb4ba1..0000000000
--- a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.blending.html
+++ /dev/null
@@ -1,37 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<link rel="match" href="2d.layer.global-states.blending-expected.html">
-<title>Canvas test: 2d.layer.global-states.blending</title>
-<h1>2d.layer.global-states.blending</h1>
-<p class="desc">Checks that layers correctly use global render states.</p>
-<canvas id="canvas" width="200" height="200">
- <p class="fallback">FAIL (fallback content)</p>
-</canvas>
-<script>
- const canvas = new OffscreenCanvas(200, 200);
- const ctx = canvas.getContext('2d');
-
- ctx.fillStyle = 'rgba(0, 0, 255, 1)';
-
- var circle = new Path2D();
- circle.arc(90, 90, 45, 0, 2 * Math.PI);
- ctx.fill(circle);
-
- ctx.globalCompositeOperation = 'multiply';
-
- ctx.beginLayer();
-
- // Enable compositing in the layer to validate that draw calls in the layer
- // 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(0, 255, 0, 1)';
- ctx.fillRect(70, 70, 75, 50);
-
- ctx.endLayer();
-
- const outputCanvas = document.getElementById("canvas");
- outputCanvas.getContext('2d').drawImage(canvas, 0, 0);
-</script>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.blending.no-shadow.no-transform-expected.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.blending.no-shadow.no-transform-expected.html
new file mode 100644
index 0000000000..c56f13f2fd
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.blending.no-shadow.no-transform-expected.html
@@ -0,0 +1,72 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<title>Canvas test: 2d.layer.global-states.blending.no-shadow.no-transform</title>
+<h1 style="font-size: 20px;">2d.layer.global-states.blending.no-shadow.no-transform</h1>
+<p class="desc">Checks that layers correctly use global render states.</p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(2, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>no-globalAlpha</div>
+ <canvas id="canvas0" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas0");
+ const ctx = canvas.getContext('2d');
+
+ // No transform.
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ // No globalAlpha.
+ ctx.globalCompositeOperation = 'multiply';
+ // No shadow.
+
+ const canvas2 = document.createElement("canvas");
+ const ctx2 = canvas2.getContext("2d");
+
+ ctx2.globalCompositeOperation = 'screen';
+ ctx2.fillStyle = 'rgba(255, 0, 0, 1)';
+ ctx2.fillRect(10, 25, 40, 50);
+ ctx2.fillStyle = 'rgba(0, 255, 0, 1)';
+ ctx2.fillRect(30, 5, 50, 40);
+
+ ctx.drawImage(canvas2, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>globalAlpha</div>
+ <canvas id="canvas1" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas1");
+ const ctx = canvas.getContext('2d');
+
+ // No transform.
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ ctx.globalAlpha = 0.75;
+ ctx.globalCompositeOperation = 'multiply';
+ // No shadow.
+
+ const canvas2 = document.createElement("canvas");
+ const ctx2 = canvas2.getContext("2d");
+
+ ctx2.globalCompositeOperation = 'screen';
+ ctx2.fillStyle = 'rgba(255, 0, 0, 1)';
+ ctx2.fillRect(10, 25, 40, 50);
+ ctx2.fillStyle = 'rgba(0, 255, 0, 1)';
+ ctx2.fillRect(30, 5, 50, 40);
+
+ ctx.drawImage(canvas2, 0, 0);
+ </script>
+</span>
+
+</div>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.blending.no-shadow.no-transform.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.blending.no-shadow.no-transform.html
new file mode 100644
index 0000000000..1f8736e0e4
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.blending.no-shadow.no-transform.html
@@ -0,0 +1,85 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<link rel="match" href="2d.layer.global-states.blending.no-shadow.no-transform-expected.html">
+<title>Canvas test: 2d.layer.global-states.blending.no-shadow.no-transform</title>
+<h1 style="font-size: 20px;">2d.layer.global-states.blending.no-shadow.no-transform</h1>
+<p class="desc">Checks that layers correctly use global render states.</p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(2, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>no-globalAlpha</div>
+ <canvas id="canvas0" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(90, 90);
+ const ctx = canvas.getContext('2d');
+
+ // No transform.
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ // No globalAlpha.
+ ctx.globalCompositeOperation = 'multiply';
+ // No shadow.
+
+ ctx.beginLayer();
+
+ // Enable compositing in the layer to validate that draw calls in the layer
+ // won't individually composite with the background.
+ ctx.globalCompositeOperation = 'screen';
+
+ 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();
+
+ const outputCanvas = document.getElementById("canvas0");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>globalAlpha</div>
+ <canvas id="canvas1" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(90, 90);
+ const ctx = canvas.getContext('2d');
+
+ // No transform.
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ ctx.globalAlpha = 0.75;
+ ctx.globalCompositeOperation = 'multiply';
+ // No shadow.
+
+ ctx.beginLayer();
+
+ // Enable compositing in the layer to validate that draw calls in the layer
+ // won't individually composite with the background.
+ ctx.globalCompositeOperation = 'screen';
+
+ 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();
+
+ const outputCanvas = document.getElementById("canvas1");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+</div>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.blending.no-shadow.no-transform.w.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.blending.no-shadow.no-transform.w.html
new file mode 100644
index 0000000000..2bd46eee66
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.blending.no-shadow.no-transform.w.html
@@ -0,0 +1,116 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<html class="reftest-wait">
+<link rel="match" href="2d.layer.global-states.blending.no-shadow.no-transform-expected.html">
+<title>Canvas test: 2d.layer.global-states.blending.no-shadow.no-transform</title>
+<h1 style="font-size: 20px;">2d.layer.global-states.blending.no-shadow.no-transform</h1>
+<p class="desc">Checks that layers correctly use global render states.</p>
+<script>pending_tests = 2;</script>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(2, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>no-globalAlpha</div>
+ <canvas id="canvas0" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script id="myWorker0" type="text/worker">
+ self.onmessage = function(e) {
+ const canvas = new OffscreenCanvas(90, 90);
+ const ctx = canvas.getContext('2d');
+
+ // No transform.
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ // No globalAlpha.
+ ctx.globalCompositeOperation = 'multiply';
+ // No shadow.
+
+ ctx.beginLayer();
+
+ // Enable compositing in the layer to validate that draw calls in the layer
+ // won't individually composite with the background.
+ ctx.globalCompositeOperation = 'screen';
+
+ 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();
+
+ const bitmap = canvas.transferToImageBitmap();
+ self.postMessage(bitmap, bitmap);
+ };
+ </script>
+ <script type="module">
+ const blob = new Blob([document.getElementById('myWorker0').textContent]);
+ const worker = new Worker(URL.createObjectURL(blob));
+ worker.addEventListener('message', msg => {
+ const outputCanvas = document.getElementById('canvas0');
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(msg.data, 0, 0);
+ if (--pending_tests == 0) {
+ document.documentElement.classList.remove('reftest-wait');
+ }
+ });
+ worker.postMessage(null);
+ </script>
+</span>
+
+<span>
+ <div>globalAlpha</div>
+ <canvas id="canvas1" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script id="myWorker1" type="text/worker">
+ self.onmessage = function(e) {
+ const canvas = new OffscreenCanvas(90, 90);
+ const ctx = canvas.getContext('2d');
+
+ // No transform.
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ ctx.globalAlpha = 0.75;
+ ctx.globalCompositeOperation = 'multiply';
+ // No shadow.
+
+ ctx.beginLayer();
+
+ // Enable compositing in the layer to validate that draw calls in the layer
+ // won't individually composite with the background.
+ ctx.globalCompositeOperation = 'screen';
+
+ 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();
+
+ const bitmap = canvas.transferToImageBitmap();
+ self.postMessage(bitmap, bitmap);
+ };
+ </script>
+ <script type="module">
+ const blob = new Blob([document.getElementById('myWorker1').textContent]);
+ const worker = new Worker(URL.createObjectURL(blob));
+ worker.addEventListener('message', msg => {
+ const outputCanvas = document.getElementById('canvas1');
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(msg.data, 0, 0);
+ if (--pending_tests == 0) {
+ document.documentElement.classList.remove('reftest-wait');
+ }
+ });
+ worker.postMessage(null);
+ </script>
+</span>
+
+</div>
+</html>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.blending.no-shadow.rotation-expected.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.blending.no-shadow.rotation-expected.html
new file mode 100644
index 0000000000..e5f8ba0db4
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.blending.no-shadow.rotation-expected.html
@@ -0,0 +1,76 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<title>Canvas test: 2d.layer.global-states.blending.no-shadow.rotation</title>
+<h1 style="font-size: 20px;">2d.layer.global-states.blending.no-shadow.rotation</h1>
+<p class="desc">Checks that layers correctly use global render states.</p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(2, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>no-globalAlpha</div>
+ <canvas id="canvas0" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas0");
+ const ctx = canvas.getContext('2d');
+
+ ctx.translate(50, 40);
+ ctx.rotate(Math.PI);
+ ctx.translate(-45, -45);
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ // No globalAlpha.
+ ctx.globalCompositeOperation = 'multiply';
+ // No shadow.
+
+ const canvas2 = document.createElement("canvas");
+ const ctx2 = canvas2.getContext("2d");
+
+ ctx2.globalCompositeOperation = 'screen';
+ ctx2.fillStyle = 'rgba(255, 0, 0, 1)';
+ ctx2.fillRect(10, 25, 40, 50);
+ ctx2.fillStyle = 'rgba(0, 255, 0, 1)';
+ ctx2.fillRect(30, 5, 50, 40);
+
+ ctx.drawImage(canvas2, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>globalAlpha</div>
+ <canvas id="canvas1" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas1");
+ const ctx = canvas.getContext('2d');
+
+ ctx.translate(50, 40);
+ ctx.rotate(Math.PI);
+ ctx.translate(-45, -45);
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ ctx.globalAlpha = 0.75;
+ ctx.globalCompositeOperation = 'multiply';
+ // No shadow.
+
+ const canvas2 = document.createElement("canvas");
+ const ctx2 = canvas2.getContext("2d");
+
+ ctx2.globalCompositeOperation = 'screen';
+ ctx2.fillStyle = 'rgba(255, 0, 0, 1)';
+ ctx2.fillRect(10, 25, 40, 50);
+ ctx2.fillStyle = 'rgba(0, 255, 0, 1)';
+ ctx2.fillRect(30, 5, 50, 40);
+
+ ctx.drawImage(canvas2, 0, 0);
+ </script>
+</span>
+
+</div>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.blending.no-shadow.rotation.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.blending.no-shadow.rotation.html
new file mode 100644
index 0000000000..0470777988
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.blending.no-shadow.rotation.html
@@ -0,0 +1,89 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<link rel="match" href="2d.layer.global-states.blending.no-shadow.rotation-expected.html">
+<title>Canvas test: 2d.layer.global-states.blending.no-shadow.rotation</title>
+<h1 style="font-size: 20px;">2d.layer.global-states.blending.no-shadow.rotation</h1>
+<p class="desc">Checks that layers correctly use global render states.</p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(2, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>no-globalAlpha</div>
+ <canvas id="canvas0" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(90, 90);
+ const ctx = canvas.getContext('2d');
+
+ ctx.translate(50, 40);
+ ctx.rotate(Math.PI);
+ ctx.translate(-45, -45);
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ // No globalAlpha.
+ ctx.globalCompositeOperation = 'multiply';
+ // No shadow.
+
+ ctx.beginLayer();
+
+ // Enable compositing in the layer to validate that draw calls in the layer
+ // won't individually composite with the background.
+ ctx.globalCompositeOperation = 'screen';
+
+ 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();
+
+ const outputCanvas = document.getElementById("canvas0");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>globalAlpha</div>
+ <canvas id="canvas1" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(90, 90);
+ const ctx = canvas.getContext('2d');
+
+ ctx.translate(50, 40);
+ ctx.rotate(Math.PI);
+ ctx.translate(-45, -45);
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ ctx.globalAlpha = 0.75;
+ ctx.globalCompositeOperation = 'multiply';
+ // No shadow.
+
+ ctx.beginLayer();
+
+ // Enable compositing in the layer to validate that draw calls in the layer
+ // won't individually composite with the background.
+ ctx.globalCompositeOperation = 'screen';
+
+ 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();
+
+ const outputCanvas = document.getElementById("canvas1");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+</div>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.blending.no-shadow.rotation.w.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.blending.no-shadow.rotation.w.html
new file mode 100644
index 0000000000..4d33b3a638
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.blending.no-shadow.rotation.w.html
@@ -0,0 +1,120 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<html class="reftest-wait">
+<link rel="match" href="2d.layer.global-states.blending.no-shadow.rotation-expected.html">
+<title>Canvas test: 2d.layer.global-states.blending.no-shadow.rotation</title>
+<h1 style="font-size: 20px;">2d.layer.global-states.blending.no-shadow.rotation</h1>
+<p class="desc">Checks that layers correctly use global render states.</p>
+<script>pending_tests = 2;</script>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(2, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>no-globalAlpha</div>
+ <canvas id="canvas0" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script id="myWorker0" type="text/worker">
+ self.onmessage = function(e) {
+ const canvas = new OffscreenCanvas(90, 90);
+ const ctx = canvas.getContext('2d');
+
+ ctx.translate(50, 40);
+ ctx.rotate(Math.PI);
+ ctx.translate(-45, -45);
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ // No globalAlpha.
+ ctx.globalCompositeOperation = 'multiply';
+ // No shadow.
+
+ ctx.beginLayer();
+
+ // Enable compositing in the layer to validate that draw calls in the layer
+ // won't individually composite with the background.
+ ctx.globalCompositeOperation = 'screen';
+
+ 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();
+
+ const bitmap = canvas.transferToImageBitmap();
+ self.postMessage(bitmap, bitmap);
+ };
+ </script>
+ <script type="module">
+ const blob = new Blob([document.getElementById('myWorker0').textContent]);
+ const worker = new Worker(URL.createObjectURL(blob));
+ worker.addEventListener('message', msg => {
+ const outputCanvas = document.getElementById('canvas0');
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(msg.data, 0, 0);
+ if (--pending_tests == 0) {
+ document.documentElement.classList.remove('reftest-wait');
+ }
+ });
+ worker.postMessage(null);
+ </script>
+</span>
+
+<span>
+ <div>globalAlpha</div>
+ <canvas id="canvas1" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script id="myWorker1" type="text/worker">
+ self.onmessage = function(e) {
+ const canvas = new OffscreenCanvas(90, 90);
+ const ctx = canvas.getContext('2d');
+
+ ctx.translate(50, 40);
+ ctx.rotate(Math.PI);
+ ctx.translate(-45, -45);
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ ctx.globalAlpha = 0.75;
+ ctx.globalCompositeOperation = 'multiply';
+ // No shadow.
+
+ ctx.beginLayer();
+
+ // Enable compositing in the layer to validate that draw calls in the layer
+ // won't individually composite with the background.
+ ctx.globalCompositeOperation = 'screen';
+
+ 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();
+
+ const bitmap = canvas.transferToImageBitmap();
+ self.postMessage(bitmap, bitmap);
+ };
+ </script>
+ <script type="module">
+ const blob = new Blob([document.getElementById('myWorker1').textContent]);
+ const worker = new Worker(URL.createObjectURL(blob));
+ worker.addEventListener('message', msg => {
+ const outputCanvas = document.getElementById('canvas1');
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(msg.data, 0, 0);
+ if (--pending_tests == 0) {
+ document.documentElement.classList.remove('reftest-wait');
+ }
+ });
+ worker.postMessage(null);
+ </script>
+</span>
+
+</div>
+</html>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.blending.shadow-expected.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.blending.shadow-expected.html
deleted file mode 100644
index 6f969074f9..0000000000
--- a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.blending.shadow-expected.html
+++ /dev/null
@@ -1,35 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<title>Canvas test: 2d.layer.global-states.blending.shadow</title>
-<h1>2d.layer.global-states.blending.shadow</h1>
-<p class="desc">Checks that layers correctly use global render states.</p>
-<canvas id="canvas" width="200" height="200">
- <p class="fallback">FAIL (fallback content)</p>
-</canvas>
-<script>
- const canvas = document.getElementById("canvas");
- const ctx = canvas.getContext('2d');
-
- ctx.fillStyle = 'rgba(0, 0, 255, 1)';
-
- var circle = new Path2D();
- circle.arc(90, 90, 45, 0, 2 * Math.PI);
- ctx.fill(circle);
-
- ctx.globalCompositeOperation = 'multiply';
- ctx.shadowOffsetX = -10;
- ctx.shadowOffsetY = 10;
- ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
- ctx.shadowBlur = 3;
-
- canvas2 = document.createElement("canvas");
- ctx2 = canvas2.getContext("2d");
-
- ctx2.globalCompositeOperation = 'screen';
- ctx2.fillStyle = 'rgba(225, 0, 0, 1)';
- ctx2.fillRect(50, 50, 75, 50);
- ctx2.fillStyle = 'rgba(0, 255, 0, 1)';
- ctx2.fillRect(70, 70, 75, 50);
-
- ctx.drawImage(canvas2, 0, 0);
-</script>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.blending.shadow.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.blending.shadow.html
deleted file mode 100644
index 2e91f3d2d1..0000000000
--- a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.blending.shadow.html
+++ /dev/null
@@ -1,41 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<link rel="match" href="2d.layer.global-states.blending.shadow-expected.html">
-<title>Canvas test: 2d.layer.global-states.blending.shadow</title>
-<h1>2d.layer.global-states.blending.shadow</h1>
-<p class="desc">Checks that layers correctly use global render states.</p>
-<canvas id="canvas" width="200" height="200">
- <p class="fallback">FAIL (fallback content)</p>
-</canvas>
-<script>
- const canvas = new OffscreenCanvas(200, 200);
- const ctx = canvas.getContext('2d');
-
- ctx.fillStyle = 'rgba(0, 0, 255, 1)';
-
- var circle = new Path2D();
- circle.arc(90, 90, 45, 0, 2 * Math.PI);
- ctx.fill(circle);
-
- ctx.globalCompositeOperation = 'multiply';
- ctx.shadowOffsetX = -10;
- ctx.shadowOffsetY = 10;
- ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
- ctx.shadowBlur = 3;
-
- ctx.beginLayer();
-
- // Enable compositing in the layer to validate that draw calls in the layer
- // 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(0, 255, 0, 1)';
- ctx.fillRect(70, 70, 75, 50);
-
- ctx.endLayer();
-
- const outputCanvas = document.getElementById("canvas");
- outputCanvas.getContext('2d').drawImage(canvas, 0, 0);
-</script>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.blending.shadow.no-transform-expected.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.blending.shadow.no-transform-expected.html
new file mode 100644
index 0000000000..debbd430c4
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.blending.shadow.no-transform-expected.html
@@ -0,0 +1,78 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<title>Canvas test: 2d.layer.global-states.blending.shadow.no-transform</title>
+<h1 style="font-size: 20px;">2d.layer.global-states.blending.shadow.no-transform</h1>
+<p class="desc">Checks that layers correctly use global render states.</p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(2, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>no-globalAlpha</div>
+ <canvas id="canvas0" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas0");
+ const ctx = canvas.getContext('2d');
+
+ // No transform.
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ // No globalAlpha.
+ ctx.globalCompositeOperation = 'multiply';
+ ctx.shadowOffsetX = -7;
+ ctx.shadowOffsetY = 7;
+ ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
+ ctx.shadowBlur = 3;
+
+ const canvas2 = document.createElement("canvas");
+ const ctx2 = canvas2.getContext("2d");
+
+ ctx2.globalCompositeOperation = 'screen';
+ ctx2.fillStyle = 'rgba(255, 0, 0, 1)';
+ ctx2.fillRect(10, 25, 40, 50);
+ ctx2.fillStyle = 'rgba(0, 255, 0, 1)';
+ ctx2.fillRect(30, 5, 50, 40);
+
+ ctx.drawImage(canvas2, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>globalAlpha</div>
+ <canvas id="canvas1" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas1");
+ const ctx = canvas.getContext('2d');
+
+ // No transform.
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ ctx.globalAlpha = 0.75;
+ ctx.globalCompositeOperation = 'multiply';
+ ctx.shadowOffsetX = -7;
+ ctx.shadowOffsetY = 7;
+ ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
+ ctx.shadowBlur = 3;
+
+ const canvas2 = document.createElement("canvas");
+ const ctx2 = canvas2.getContext("2d");
+
+ ctx2.globalCompositeOperation = 'screen';
+ ctx2.fillStyle = 'rgba(255, 0, 0, 1)';
+ ctx2.fillRect(10, 25, 40, 50);
+ ctx2.fillStyle = 'rgba(0, 255, 0, 1)';
+ ctx2.fillRect(30, 5, 50, 40);
+
+ ctx.drawImage(canvas2, 0, 0);
+ </script>
+</span>
+
+</div>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.blending.shadow.no-transform.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.blending.shadow.no-transform.html
new file mode 100644
index 0000000000..c6f0239c39
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.blending.shadow.no-transform.html
@@ -0,0 +1,91 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<link rel="match" href="2d.layer.global-states.blending.shadow.no-transform-expected.html">
+<title>Canvas test: 2d.layer.global-states.blending.shadow.no-transform</title>
+<h1 style="font-size: 20px;">2d.layer.global-states.blending.shadow.no-transform</h1>
+<p class="desc">Checks that layers correctly use global render states.</p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(2, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>no-globalAlpha</div>
+ <canvas id="canvas0" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(90, 90);
+ const ctx = canvas.getContext('2d');
+
+ // No transform.
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ // No globalAlpha.
+ ctx.globalCompositeOperation = 'multiply';
+ ctx.shadowOffsetX = -7;
+ ctx.shadowOffsetY = 7;
+ ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
+ ctx.shadowBlur = 3;
+
+ ctx.beginLayer();
+
+ // Enable compositing in the layer to validate that draw calls in the layer
+ // won't individually composite with the background.
+ ctx.globalCompositeOperation = 'screen';
+
+ 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();
+
+ const outputCanvas = document.getElementById("canvas0");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>globalAlpha</div>
+ <canvas id="canvas1" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(90, 90);
+ const ctx = canvas.getContext('2d');
+
+ // No transform.
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ ctx.globalAlpha = 0.75;
+ ctx.globalCompositeOperation = 'multiply';
+ ctx.shadowOffsetX = -7;
+ ctx.shadowOffsetY = 7;
+ ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
+ ctx.shadowBlur = 3;
+
+ ctx.beginLayer();
+
+ // Enable compositing in the layer to validate that draw calls in the layer
+ // won't individually composite with the background.
+ ctx.globalCompositeOperation = 'screen';
+
+ 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();
+
+ const outputCanvas = document.getElementById("canvas1");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+</div>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.blending.shadow.no-transform.w.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.blending.shadow.no-transform.w.html
new file mode 100644
index 0000000000..0be246ebfb
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.blending.shadow.no-transform.w.html
@@ -0,0 +1,122 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<html class="reftest-wait">
+<link rel="match" href="2d.layer.global-states.blending.shadow.no-transform-expected.html">
+<title>Canvas test: 2d.layer.global-states.blending.shadow.no-transform</title>
+<h1 style="font-size: 20px;">2d.layer.global-states.blending.shadow.no-transform</h1>
+<p class="desc">Checks that layers correctly use global render states.</p>
+<script>pending_tests = 2;</script>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(2, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>no-globalAlpha</div>
+ <canvas id="canvas0" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script id="myWorker0" type="text/worker">
+ self.onmessage = function(e) {
+ const canvas = new OffscreenCanvas(90, 90);
+ const ctx = canvas.getContext('2d');
+
+ // No transform.
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ // No globalAlpha.
+ ctx.globalCompositeOperation = 'multiply';
+ ctx.shadowOffsetX = -7;
+ ctx.shadowOffsetY = 7;
+ ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
+ ctx.shadowBlur = 3;
+
+ ctx.beginLayer();
+
+ // Enable compositing in the layer to validate that draw calls in the layer
+ // won't individually composite with the background.
+ ctx.globalCompositeOperation = 'screen';
+
+ 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();
+
+ const bitmap = canvas.transferToImageBitmap();
+ self.postMessage(bitmap, bitmap);
+ };
+ </script>
+ <script type="module">
+ const blob = new Blob([document.getElementById('myWorker0').textContent]);
+ const worker = new Worker(URL.createObjectURL(blob));
+ worker.addEventListener('message', msg => {
+ const outputCanvas = document.getElementById('canvas0');
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(msg.data, 0, 0);
+ if (--pending_tests == 0) {
+ document.documentElement.classList.remove('reftest-wait');
+ }
+ });
+ worker.postMessage(null);
+ </script>
+</span>
+
+<span>
+ <div>globalAlpha</div>
+ <canvas id="canvas1" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script id="myWorker1" type="text/worker">
+ self.onmessage = function(e) {
+ const canvas = new OffscreenCanvas(90, 90);
+ const ctx = canvas.getContext('2d');
+
+ // No transform.
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ ctx.globalAlpha = 0.75;
+ ctx.globalCompositeOperation = 'multiply';
+ ctx.shadowOffsetX = -7;
+ ctx.shadowOffsetY = 7;
+ ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
+ ctx.shadowBlur = 3;
+
+ ctx.beginLayer();
+
+ // Enable compositing in the layer to validate that draw calls in the layer
+ // won't individually composite with the background.
+ ctx.globalCompositeOperation = 'screen';
+
+ 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();
+
+ const bitmap = canvas.transferToImageBitmap();
+ self.postMessage(bitmap, bitmap);
+ };
+ </script>
+ <script type="module">
+ const blob = new Blob([document.getElementById('myWorker1').textContent]);
+ const worker = new Worker(URL.createObjectURL(blob));
+ worker.addEventListener('message', msg => {
+ const outputCanvas = document.getElementById('canvas1');
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(msg.data, 0, 0);
+ if (--pending_tests == 0) {
+ document.documentElement.classList.remove('reftest-wait');
+ }
+ });
+ worker.postMessage(null);
+ </script>
+</span>
+
+</div>
+</html>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.blending.shadow.rotation-expected.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.blending.shadow.rotation-expected.html
new file mode 100644
index 0000000000..75a55e591b
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.blending.shadow.rotation-expected.html
@@ -0,0 +1,82 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<title>Canvas test: 2d.layer.global-states.blending.shadow.rotation</title>
+<h1 style="font-size: 20px;">2d.layer.global-states.blending.shadow.rotation</h1>
+<p class="desc">Checks that layers correctly use global render states.</p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(2, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>no-globalAlpha</div>
+ <canvas id="canvas0" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas0");
+ const ctx = canvas.getContext('2d');
+
+ ctx.translate(50, 40);
+ ctx.rotate(Math.PI);
+ ctx.translate(-45, -45);
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ // No globalAlpha.
+ ctx.globalCompositeOperation = 'multiply';
+ ctx.shadowOffsetX = -7;
+ ctx.shadowOffsetY = 7;
+ ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
+ ctx.shadowBlur = 3;
+
+ const canvas2 = document.createElement("canvas");
+ const ctx2 = canvas2.getContext("2d");
+
+ ctx2.globalCompositeOperation = 'screen';
+ ctx2.fillStyle = 'rgba(255, 0, 0, 1)';
+ ctx2.fillRect(10, 25, 40, 50);
+ ctx2.fillStyle = 'rgba(0, 255, 0, 1)';
+ ctx2.fillRect(30, 5, 50, 40);
+
+ ctx.drawImage(canvas2, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>globalAlpha</div>
+ <canvas id="canvas1" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas1");
+ const ctx = canvas.getContext('2d');
+
+ ctx.translate(50, 40);
+ ctx.rotate(Math.PI);
+ ctx.translate(-45, -45);
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ ctx.globalAlpha = 0.75;
+ ctx.globalCompositeOperation = 'multiply';
+ ctx.shadowOffsetX = -7;
+ ctx.shadowOffsetY = 7;
+ ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
+ ctx.shadowBlur = 3;
+
+ const canvas2 = document.createElement("canvas");
+ const ctx2 = canvas2.getContext("2d");
+
+ ctx2.globalCompositeOperation = 'screen';
+ ctx2.fillStyle = 'rgba(255, 0, 0, 1)';
+ ctx2.fillRect(10, 25, 40, 50);
+ ctx2.fillStyle = 'rgba(0, 255, 0, 1)';
+ ctx2.fillRect(30, 5, 50, 40);
+
+ ctx.drawImage(canvas2, 0, 0);
+ </script>
+</span>
+
+</div>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.blending.shadow.rotation.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.blending.shadow.rotation.html
new file mode 100644
index 0000000000..aac9d86e66
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.blending.shadow.rotation.html
@@ -0,0 +1,95 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<link rel="match" href="2d.layer.global-states.blending.shadow.rotation-expected.html">
+<title>Canvas test: 2d.layer.global-states.blending.shadow.rotation</title>
+<h1 style="font-size: 20px;">2d.layer.global-states.blending.shadow.rotation</h1>
+<p class="desc">Checks that layers correctly use global render states.</p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(2, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>no-globalAlpha</div>
+ <canvas id="canvas0" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(90, 90);
+ const ctx = canvas.getContext('2d');
+
+ ctx.translate(50, 40);
+ ctx.rotate(Math.PI);
+ ctx.translate(-45, -45);
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ // No globalAlpha.
+ ctx.globalCompositeOperation = 'multiply';
+ ctx.shadowOffsetX = -7;
+ ctx.shadowOffsetY = 7;
+ ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
+ ctx.shadowBlur = 3;
+
+ ctx.beginLayer();
+
+ // Enable compositing in the layer to validate that draw calls in the layer
+ // won't individually composite with the background.
+ ctx.globalCompositeOperation = 'screen';
+
+ 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();
+
+ const outputCanvas = document.getElementById("canvas0");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>globalAlpha</div>
+ <canvas id="canvas1" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(90, 90);
+ const ctx = canvas.getContext('2d');
+
+ ctx.translate(50, 40);
+ ctx.rotate(Math.PI);
+ ctx.translate(-45, -45);
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ ctx.globalAlpha = 0.75;
+ ctx.globalCompositeOperation = 'multiply';
+ ctx.shadowOffsetX = -7;
+ ctx.shadowOffsetY = 7;
+ ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
+ ctx.shadowBlur = 3;
+
+ ctx.beginLayer();
+
+ // Enable compositing in the layer to validate that draw calls in the layer
+ // won't individually composite with the background.
+ ctx.globalCompositeOperation = 'screen';
+
+ 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();
+
+ const outputCanvas = document.getElementById("canvas1");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+</div>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.blending.shadow.rotation.w.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.blending.shadow.rotation.w.html
new file mode 100644
index 0000000000..86067b7299
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.blending.shadow.rotation.w.html
@@ -0,0 +1,126 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<html class="reftest-wait">
+<link rel="match" href="2d.layer.global-states.blending.shadow.rotation-expected.html">
+<title>Canvas test: 2d.layer.global-states.blending.shadow.rotation</title>
+<h1 style="font-size: 20px;">2d.layer.global-states.blending.shadow.rotation</h1>
+<p class="desc">Checks that layers correctly use global render states.</p>
+<script>pending_tests = 2;</script>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(2, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>no-globalAlpha</div>
+ <canvas id="canvas0" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script id="myWorker0" type="text/worker">
+ self.onmessage = function(e) {
+ const canvas = new OffscreenCanvas(90, 90);
+ const ctx = canvas.getContext('2d');
+
+ ctx.translate(50, 40);
+ ctx.rotate(Math.PI);
+ ctx.translate(-45, -45);
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ // No globalAlpha.
+ ctx.globalCompositeOperation = 'multiply';
+ ctx.shadowOffsetX = -7;
+ ctx.shadowOffsetY = 7;
+ ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
+ ctx.shadowBlur = 3;
+
+ ctx.beginLayer();
+
+ // Enable compositing in the layer to validate that draw calls in the layer
+ // won't individually composite with the background.
+ ctx.globalCompositeOperation = 'screen';
+
+ 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();
+
+ const bitmap = canvas.transferToImageBitmap();
+ self.postMessage(bitmap, bitmap);
+ };
+ </script>
+ <script type="module">
+ const blob = new Blob([document.getElementById('myWorker0').textContent]);
+ const worker = new Worker(URL.createObjectURL(blob));
+ worker.addEventListener('message', msg => {
+ const outputCanvas = document.getElementById('canvas0');
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(msg.data, 0, 0);
+ if (--pending_tests == 0) {
+ document.documentElement.classList.remove('reftest-wait');
+ }
+ });
+ worker.postMessage(null);
+ </script>
+</span>
+
+<span>
+ <div>globalAlpha</div>
+ <canvas id="canvas1" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script id="myWorker1" type="text/worker">
+ self.onmessage = function(e) {
+ const canvas = new OffscreenCanvas(90, 90);
+ const ctx = canvas.getContext('2d');
+
+ ctx.translate(50, 40);
+ ctx.rotate(Math.PI);
+ ctx.translate(-45, -45);
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ ctx.globalAlpha = 0.75;
+ ctx.globalCompositeOperation = 'multiply';
+ ctx.shadowOffsetX = -7;
+ ctx.shadowOffsetY = 7;
+ ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
+ ctx.shadowBlur = 3;
+
+ ctx.beginLayer();
+
+ // Enable compositing in the layer to validate that draw calls in the layer
+ // won't individually composite with the background.
+ ctx.globalCompositeOperation = 'screen';
+
+ 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();
+
+ const bitmap = canvas.transferToImageBitmap();
+ self.postMessage(bitmap, bitmap);
+ };
+ </script>
+ <script type="module">
+ const blob = new Blob([document.getElementById('myWorker1').textContent]);
+ const worker = new Worker(URL.createObjectURL(blob));
+ worker.addEventListener('message', msg => {
+ const outputCanvas = document.getElementById('canvas1');
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(msg.data, 0, 0);
+ if (--pending_tests == 0) {
+ document.documentElement.classList.remove('reftest-wait');
+ }
+ });
+ worker.postMessage(null);
+ </script>
+</span>
+
+</div>
+</html>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.blending.shadow.w.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.blending.shadow.w.html
deleted file mode 100644
index d8e20d0479..0000000000
--- a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.blending.shadow.w.html
+++ /dev/null
@@ -1,55 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<html class="reftest-wait">
-<link rel="match" href="2d.layer.global-states.blending.shadow-expected.html">
-<title>Canvas test: 2d.layer.global-states.blending.shadow</title>
-<h1>2d.layer.global-states.blending.shadow</h1>
-<p class="desc">Checks that layers correctly use global render states.</p>
-<canvas id="canvas" width="200" height="200">
- <p class="fallback">FAIL (fallback content)</p>
-</canvas>
-<script id='myWorker' type='text/worker'>
- self.onmessage = function(e) {
- const canvas = new OffscreenCanvas(200, 200);
- const ctx = canvas.getContext('2d');
-
- ctx.fillStyle = 'rgba(0, 0, 255, 1)';
-
- var circle = new Path2D();
- circle.arc(90, 90, 45, 0, 2 * Math.PI);
- ctx.fill(circle);
-
- ctx.globalCompositeOperation = 'multiply';
- ctx.shadowOffsetX = -10;
- ctx.shadowOffsetY = 10;
- ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
- ctx.shadowBlur = 3;
-
- ctx.beginLayer();
-
- // Enable compositing in the layer to validate that draw calls in the layer
- // 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(0, 255, 0, 1)';
- ctx.fillRect(70, 70, 75, 50);
-
- ctx.endLayer();
-
- const bitmap = canvas.transferToImageBitmap();
- self.postMessage(bitmap, bitmap);
- };
-</script>
-<script>
- const blob = new Blob([document.getElementById('myWorker').textContent]);
- const worker = new Worker(URL.createObjectURL(blob));
- worker.addEventListener('message', msg => {
- const outputCtx = document.getElementById("canvas").getContext('2d');
- outputCtx.drawImage(msg.data, 0, 0);
- document.documentElement.classList.remove("reftest-wait");
- });
- worker.postMessage(null);
-</script>
-</html>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.blending.w.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.blending.w.html
deleted file mode 100644
index 8964e97713..0000000000
--- a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.blending.w.html
+++ /dev/null
@@ -1,51 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<html class="reftest-wait">
-<link rel="match" href="2d.layer.global-states.blending-expected.html">
-<title>Canvas test: 2d.layer.global-states.blending</title>
-<h1>2d.layer.global-states.blending</h1>
-<p class="desc">Checks that layers correctly use global render states.</p>
-<canvas id="canvas" width="200" height="200">
- <p class="fallback">FAIL (fallback content)</p>
-</canvas>
-<script id='myWorker' type='text/worker'>
- self.onmessage = function(e) {
- const canvas = new OffscreenCanvas(200, 200);
- const ctx = canvas.getContext('2d');
-
- ctx.fillStyle = 'rgba(0, 0, 255, 1)';
-
- var circle = new Path2D();
- circle.arc(90, 90, 45, 0, 2 * Math.PI);
- ctx.fill(circle);
-
- ctx.globalCompositeOperation = 'multiply';
-
- ctx.beginLayer();
-
- // Enable compositing in the layer to validate that draw calls in the layer
- // 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(0, 255, 0, 1)';
- ctx.fillRect(70, 70, 75, 50);
-
- ctx.endLayer();
-
- const bitmap = canvas.transferToImageBitmap();
- self.postMessage(bitmap, bitmap);
- };
-</script>
-<script>
- const blob = new Blob([document.getElementById('myWorker').textContent]);
- const worker = new Worker(URL.createObjectURL(blob));
- worker.addEventListener('message', msg => {
- const outputCtx = document.getElementById("canvas").getContext('2d');
- outputCtx.drawImage(msg.data, 0, 0);
- document.documentElement.classList.remove("reftest-wait");
- });
- worker.postMessage(null);
-</script>
-</html>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.composite-expected.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.composite-expected.html
deleted file mode 100644
index ed7669c4cf..0000000000
--- a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.composite-expected.html
+++ /dev/null
@@ -1,31 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<title>Canvas test: 2d.layer.global-states.composite</title>
-<h1>2d.layer.global-states.composite</h1>
-<p class="desc">Checks that layers correctly use global render states.</p>
-<canvas id="canvas" width="200" height="200">
- <p class="fallback">FAIL (fallback content)</p>
-</canvas>
-<script>
- const canvas = document.getElementById("canvas");
- const ctx = canvas.getContext('2d');
-
- ctx.fillStyle = 'rgba(0, 0, 255, 1)';
-
- var circle = new Path2D();
- circle.arc(90, 90, 45, 0, 2 * Math.PI);
- ctx.fill(circle);
-
- ctx.globalCompositeOperation = 'source-in';
-
- canvas2 = document.createElement("canvas");
- ctx2 = canvas2.getContext("2d");
-
- ctx2.globalCompositeOperation = 'screen';
- ctx2.fillStyle = 'rgba(225, 0, 0, 1)';
- ctx2.fillRect(50, 50, 75, 50);
- ctx2.fillStyle = 'rgba(0, 255, 0, 1)';
- ctx2.fillRect(70, 70, 75, 50);
-
- ctx.drawImage(canvas2, 0, 0);
-</script>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.composite.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.composite.html
deleted file mode 100644
index 84fb4b3d95..0000000000
--- a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.composite.html
+++ /dev/null
@@ -1,37 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<link rel="match" href="2d.layer.global-states.composite-expected.html">
-<title>Canvas test: 2d.layer.global-states.composite</title>
-<h1>2d.layer.global-states.composite</h1>
-<p class="desc">Checks that layers correctly use global render states.</p>
-<canvas id="canvas" width="200" height="200">
- <p class="fallback">FAIL (fallback content)</p>
-</canvas>
-<script>
- const canvas = new OffscreenCanvas(200, 200);
- const ctx = canvas.getContext('2d');
-
- ctx.fillStyle = 'rgba(0, 0, 255, 1)';
-
- var circle = new Path2D();
- circle.arc(90, 90, 45, 0, 2 * Math.PI);
- ctx.fill(circle);
-
- ctx.globalCompositeOperation = 'source-in';
-
- ctx.beginLayer();
-
- // Enable compositing in the layer to validate that draw calls in the layer
- // 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(0, 255, 0, 1)';
- ctx.fillRect(70, 70, 75, 50);
-
- ctx.endLayer();
-
- const outputCanvas = document.getElementById("canvas");
- outputCanvas.getContext('2d').drawImage(canvas, 0, 0);
-</script>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.composite.no-shadow.no-transform-expected.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.composite.no-shadow.no-transform-expected.html
new file mode 100644
index 0000000000..cf87559582
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.composite.no-shadow.no-transform-expected.html
@@ -0,0 +1,72 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<title>Canvas test: 2d.layer.global-states.composite.no-shadow.no-transform</title>
+<h1 style="font-size: 20px;">2d.layer.global-states.composite.no-shadow.no-transform</h1>
+<p class="desc">Checks that layers correctly use global render states.</p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(2, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>no-globalAlpha</div>
+ <canvas id="canvas0" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas0");
+ const ctx = canvas.getContext('2d');
+
+ // No transform.
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ // No globalAlpha.
+ ctx.globalCompositeOperation = 'source-in';
+ // No shadow.
+
+ const canvas2 = document.createElement("canvas");
+ const ctx2 = canvas2.getContext("2d");
+
+ ctx2.globalCompositeOperation = 'screen';
+ ctx2.fillStyle = 'rgba(255, 0, 0, 1)';
+ ctx2.fillRect(10, 25, 40, 50);
+ ctx2.fillStyle = 'rgba(0, 255, 0, 1)';
+ ctx2.fillRect(30, 5, 50, 40);
+
+ ctx.drawImage(canvas2, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>globalAlpha</div>
+ <canvas id="canvas1" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas1");
+ const ctx = canvas.getContext('2d');
+
+ // No transform.
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ ctx.globalAlpha = 0.75;
+ ctx.globalCompositeOperation = 'source-in';
+ // No shadow.
+
+ const canvas2 = document.createElement("canvas");
+ const ctx2 = canvas2.getContext("2d");
+
+ ctx2.globalCompositeOperation = 'screen';
+ ctx2.fillStyle = 'rgba(255, 0, 0, 1)';
+ ctx2.fillRect(10, 25, 40, 50);
+ ctx2.fillStyle = 'rgba(0, 255, 0, 1)';
+ ctx2.fillRect(30, 5, 50, 40);
+
+ ctx.drawImage(canvas2, 0, 0);
+ </script>
+</span>
+
+</div>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.composite.no-shadow.no-transform.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.composite.no-shadow.no-transform.html
new file mode 100644
index 0000000000..69dc916d7d
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.composite.no-shadow.no-transform.html
@@ -0,0 +1,85 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<link rel="match" href="2d.layer.global-states.composite.no-shadow.no-transform-expected.html">
+<title>Canvas test: 2d.layer.global-states.composite.no-shadow.no-transform</title>
+<h1 style="font-size: 20px;">2d.layer.global-states.composite.no-shadow.no-transform</h1>
+<p class="desc">Checks that layers correctly use global render states.</p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(2, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>no-globalAlpha</div>
+ <canvas id="canvas0" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(90, 90);
+ const ctx = canvas.getContext('2d');
+
+ // No transform.
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ // No globalAlpha.
+ ctx.globalCompositeOperation = 'source-in';
+ // No shadow.
+
+ ctx.beginLayer();
+
+ // Enable compositing in the layer to validate that draw calls in the layer
+ // won't individually composite with the background.
+ ctx.globalCompositeOperation = 'screen';
+
+ 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();
+
+ const outputCanvas = document.getElementById("canvas0");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>globalAlpha</div>
+ <canvas id="canvas1" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(90, 90);
+ const ctx = canvas.getContext('2d');
+
+ // No transform.
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ ctx.globalAlpha = 0.75;
+ ctx.globalCompositeOperation = 'source-in';
+ // No shadow.
+
+ ctx.beginLayer();
+
+ // Enable compositing in the layer to validate that draw calls in the layer
+ // won't individually composite with the background.
+ ctx.globalCompositeOperation = 'screen';
+
+ 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();
+
+ const outputCanvas = document.getElementById("canvas1");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+</div>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.composite.no-shadow.no-transform.w.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.composite.no-shadow.no-transform.w.html
new file mode 100644
index 0000000000..aa358b57bc
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.composite.no-shadow.no-transform.w.html
@@ -0,0 +1,116 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<html class="reftest-wait">
+<link rel="match" href="2d.layer.global-states.composite.no-shadow.no-transform-expected.html">
+<title>Canvas test: 2d.layer.global-states.composite.no-shadow.no-transform</title>
+<h1 style="font-size: 20px;">2d.layer.global-states.composite.no-shadow.no-transform</h1>
+<p class="desc">Checks that layers correctly use global render states.</p>
+<script>pending_tests = 2;</script>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(2, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>no-globalAlpha</div>
+ <canvas id="canvas0" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script id="myWorker0" type="text/worker">
+ self.onmessage = function(e) {
+ const canvas = new OffscreenCanvas(90, 90);
+ const ctx = canvas.getContext('2d');
+
+ // No transform.
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ // No globalAlpha.
+ ctx.globalCompositeOperation = 'source-in';
+ // No shadow.
+
+ ctx.beginLayer();
+
+ // Enable compositing in the layer to validate that draw calls in the layer
+ // won't individually composite with the background.
+ ctx.globalCompositeOperation = 'screen';
+
+ 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();
+
+ const bitmap = canvas.transferToImageBitmap();
+ self.postMessage(bitmap, bitmap);
+ };
+ </script>
+ <script type="module">
+ const blob = new Blob([document.getElementById('myWorker0').textContent]);
+ const worker = new Worker(URL.createObjectURL(blob));
+ worker.addEventListener('message', msg => {
+ const outputCanvas = document.getElementById('canvas0');
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(msg.data, 0, 0);
+ if (--pending_tests == 0) {
+ document.documentElement.classList.remove('reftest-wait');
+ }
+ });
+ worker.postMessage(null);
+ </script>
+</span>
+
+<span>
+ <div>globalAlpha</div>
+ <canvas id="canvas1" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script id="myWorker1" type="text/worker">
+ self.onmessage = function(e) {
+ const canvas = new OffscreenCanvas(90, 90);
+ const ctx = canvas.getContext('2d');
+
+ // No transform.
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ ctx.globalAlpha = 0.75;
+ ctx.globalCompositeOperation = 'source-in';
+ // No shadow.
+
+ ctx.beginLayer();
+
+ // Enable compositing in the layer to validate that draw calls in the layer
+ // won't individually composite with the background.
+ ctx.globalCompositeOperation = 'screen';
+
+ 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();
+
+ const bitmap = canvas.transferToImageBitmap();
+ self.postMessage(bitmap, bitmap);
+ };
+ </script>
+ <script type="module">
+ const blob = new Blob([document.getElementById('myWorker1').textContent]);
+ const worker = new Worker(URL.createObjectURL(blob));
+ worker.addEventListener('message', msg => {
+ const outputCanvas = document.getElementById('canvas1');
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(msg.data, 0, 0);
+ if (--pending_tests == 0) {
+ document.documentElement.classList.remove('reftest-wait');
+ }
+ });
+ worker.postMessage(null);
+ </script>
+</span>
+
+</div>
+</html>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.composite.no-shadow.rotation-expected.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.composite.no-shadow.rotation-expected.html
new file mode 100644
index 0000000000..2f9bb208fb
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.composite.no-shadow.rotation-expected.html
@@ -0,0 +1,76 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<title>Canvas test: 2d.layer.global-states.composite.no-shadow.rotation</title>
+<h1 style="font-size: 20px;">2d.layer.global-states.composite.no-shadow.rotation</h1>
+<p class="desc">Checks that layers correctly use global render states.</p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(2, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>no-globalAlpha</div>
+ <canvas id="canvas0" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas0");
+ const ctx = canvas.getContext('2d');
+
+ ctx.translate(50, 40);
+ ctx.rotate(Math.PI);
+ ctx.translate(-45, -45);
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ // No globalAlpha.
+ ctx.globalCompositeOperation = 'source-in';
+ // No shadow.
+
+ const canvas2 = document.createElement("canvas");
+ const ctx2 = canvas2.getContext("2d");
+
+ ctx2.globalCompositeOperation = 'screen';
+ ctx2.fillStyle = 'rgba(255, 0, 0, 1)';
+ ctx2.fillRect(10, 25, 40, 50);
+ ctx2.fillStyle = 'rgba(0, 255, 0, 1)';
+ ctx2.fillRect(30, 5, 50, 40);
+
+ ctx.drawImage(canvas2, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>globalAlpha</div>
+ <canvas id="canvas1" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas1");
+ const ctx = canvas.getContext('2d');
+
+ ctx.translate(50, 40);
+ ctx.rotate(Math.PI);
+ ctx.translate(-45, -45);
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ ctx.globalAlpha = 0.75;
+ ctx.globalCompositeOperation = 'source-in';
+ // No shadow.
+
+ const canvas2 = document.createElement("canvas");
+ const ctx2 = canvas2.getContext("2d");
+
+ ctx2.globalCompositeOperation = 'screen';
+ ctx2.fillStyle = 'rgba(255, 0, 0, 1)';
+ ctx2.fillRect(10, 25, 40, 50);
+ ctx2.fillStyle = 'rgba(0, 255, 0, 1)';
+ ctx2.fillRect(30, 5, 50, 40);
+
+ ctx.drawImage(canvas2, 0, 0);
+ </script>
+</span>
+
+</div>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.composite.no-shadow.rotation.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.composite.no-shadow.rotation.html
new file mode 100644
index 0000000000..d0d08f9835
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.composite.no-shadow.rotation.html
@@ -0,0 +1,89 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<link rel="match" href="2d.layer.global-states.composite.no-shadow.rotation-expected.html">
+<title>Canvas test: 2d.layer.global-states.composite.no-shadow.rotation</title>
+<h1 style="font-size: 20px;">2d.layer.global-states.composite.no-shadow.rotation</h1>
+<p class="desc">Checks that layers correctly use global render states.</p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(2, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>no-globalAlpha</div>
+ <canvas id="canvas0" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(90, 90);
+ const ctx = canvas.getContext('2d');
+
+ ctx.translate(50, 40);
+ ctx.rotate(Math.PI);
+ ctx.translate(-45, -45);
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ // No globalAlpha.
+ ctx.globalCompositeOperation = 'source-in';
+ // No shadow.
+
+ ctx.beginLayer();
+
+ // Enable compositing in the layer to validate that draw calls in the layer
+ // won't individually composite with the background.
+ ctx.globalCompositeOperation = 'screen';
+
+ 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();
+
+ const outputCanvas = document.getElementById("canvas0");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>globalAlpha</div>
+ <canvas id="canvas1" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(90, 90);
+ const ctx = canvas.getContext('2d');
+
+ ctx.translate(50, 40);
+ ctx.rotate(Math.PI);
+ ctx.translate(-45, -45);
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ ctx.globalAlpha = 0.75;
+ ctx.globalCompositeOperation = 'source-in';
+ // No shadow.
+
+ ctx.beginLayer();
+
+ // Enable compositing in the layer to validate that draw calls in the layer
+ // won't individually composite with the background.
+ ctx.globalCompositeOperation = 'screen';
+
+ 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();
+
+ const outputCanvas = document.getElementById("canvas1");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+</div>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.composite.no-shadow.rotation.w.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.composite.no-shadow.rotation.w.html
new file mode 100644
index 0000000000..5e2cd0783d
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.composite.no-shadow.rotation.w.html
@@ -0,0 +1,120 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<html class="reftest-wait">
+<link rel="match" href="2d.layer.global-states.composite.no-shadow.rotation-expected.html">
+<title>Canvas test: 2d.layer.global-states.composite.no-shadow.rotation</title>
+<h1 style="font-size: 20px;">2d.layer.global-states.composite.no-shadow.rotation</h1>
+<p class="desc">Checks that layers correctly use global render states.</p>
+<script>pending_tests = 2;</script>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(2, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>no-globalAlpha</div>
+ <canvas id="canvas0" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script id="myWorker0" type="text/worker">
+ self.onmessage = function(e) {
+ const canvas = new OffscreenCanvas(90, 90);
+ const ctx = canvas.getContext('2d');
+
+ ctx.translate(50, 40);
+ ctx.rotate(Math.PI);
+ ctx.translate(-45, -45);
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ // No globalAlpha.
+ ctx.globalCompositeOperation = 'source-in';
+ // No shadow.
+
+ ctx.beginLayer();
+
+ // Enable compositing in the layer to validate that draw calls in the layer
+ // won't individually composite with the background.
+ ctx.globalCompositeOperation = 'screen';
+
+ 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();
+
+ const bitmap = canvas.transferToImageBitmap();
+ self.postMessage(bitmap, bitmap);
+ };
+ </script>
+ <script type="module">
+ const blob = new Blob([document.getElementById('myWorker0').textContent]);
+ const worker = new Worker(URL.createObjectURL(blob));
+ worker.addEventListener('message', msg => {
+ const outputCanvas = document.getElementById('canvas0');
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(msg.data, 0, 0);
+ if (--pending_tests == 0) {
+ document.documentElement.classList.remove('reftest-wait');
+ }
+ });
+ worker.postMessage(null);
+ </script>
+</span>
+
+<span>
+ <div>globalAlpha</div>
+ <canvas id="canvas1" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script id="myWorker1" type="text/worker">
+ self.onmessage = function(e) {
+ const canvas = new OffscreenCanvas(90, 90);
+ const ctx = canvas.getContext('2d');
+
+ ctx.translate(50, 40);
+ ctx.rotate(Math.PI);
+ ctx.translate(-45, -45);
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ ctx.globalAlpha = 0.75;
+ ctx.globalCompositeOperation = 'source-in';
+ // No shadow.
+
+ ctx.beginLayer();
+
+ // Enable compositing in the layer to validate that draw calls in the layer
+ // won't individually composite with the background.
+ ctx.globalCompositeOperation = 'screen';
+
+ 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();
+
+ const bitmap = canvas.transferToImageBitmap();
+ self.postMessage(bitmap, bitmap);
+ };
+ </script>
+ <script type="module">
+ const blob = new Blob([document.getElementById('myWorker1').textContent]);
+ const worker = new Worker(URL.createObjectURL(blob));
+ worker.addEventListener('message', msg => {
+ const outputCanvas = document.getElementById('canvas1');
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(msg.data, 0, 0);
+ if (--pending_tests == 0) {
+ document.documentElement.classList.remove('reftest-wait');
+ }
+ });
+ worker.postMessage(null);
+ </script>
+</span>
+
+</div>
+</html>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.composite.shadow-expected.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.composite.shadow-expected.html
deleted file mode 100644
index b687c27f47..0000000000
--- a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.composite.shadow-expected.html
+++ /dev/null
@@ -1,35 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<title>Canvas test: 2d.layer.global-states.composite.shadow</title>
-<h1>2d.layer.global-states.composite.shadow</h1>
-<p class="desc">Checks that layers correctly use global render states.</p>
-<canvas id="canvas" width="200" height="200">
- <p class="fallback">FAIL (fallback content)</p>
-</canvas>
-<script>
- const canvas = document.getElementById("canvas");
- const ctx = canvas.getContext('2d');
-
- ctx.fillStyle = 'rgba(0, 0, 255, 1)';
-
- var circle = new Path2D();
- circle.arc(90, 90, 45, 0, 2 * Math.PI);
- ctx.fill(circle);
-
- ctx.globalCompositeOperation = 'source-in';
- ctx.shadowOffsetX = -10;
- ctx.shadowOffsetY = 10;
- ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
- ctx.shadowBlur = 3;
-
- canvas2 = document.createElement("canvas");
- ctx2 = canvas2.getContext("2d");
-
- ctx2.globalCompositeOperation = 'screen';
- ctx2.fillStyle = 'rgba(225, 0, 0, 1)';
- ctx2.fillRect(50, 50, 75, 50);
- ctx2.fillStyle = 'rgba(0, 255, 0, 1)';
- ctx2.fillRect(70, 70, 75, 50);
-
- ctx.drawImage(canvas2, 0, 0);
-</script>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.composite.shadow.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.composite.shadow.html
deleted file mode 100644
index 1e3ab4d6a0..0000000000
--- a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.composite.shadow.html
+++ /dev/null
@@ -1,41 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<link rel="match" href="2d.layer.global-states.composite.shadow-expected.html">
-<title>Canvas test: 2d.layer.global-states.composite.shadow</title>
-<h1>2d.layer.global-states.composite.shadow</h1>
-<p class="desc">Checks that layers correctly use global render states.</p>
-<canvas id="canvas" width="200" height="200">
- <p class="fallback">FAIL (fallback content)</p>
-</canvas>
-<script>
- const canvas = new OffscreenCanvas(200, 200);
- const ctx = canvas.getContext('2d');
-
- ctx.fillStyle = 'rgba(0, 0, 255, 1)';
-
- var circle = new Path2D();
- circle.arc(90, 90, 45, 0, 2 * Math.PI);
- ctx.fill(circle);
-
- ctx.globalCompositeOperation = 'source-in';
- ctx.shadowOffsetX = -10;
- ctx.shadowOffsetY = 10;
- ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
- ctx.shadowBlur = 3;
-
- ctx.beginLayer();
-
- // Enable compositing in the layer to validate that draw calls in the layer
- // 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(0, 255, 0, 1)';
- ctx.fillRect(70, 70, 75, 50);
-
- ctx.endLayer();
-
- const outputCanvas = document.getElementById("canvas");
- outputCanvas.getContext('2d').drawImage(canvas, 0, 0);
-</script>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.composite.shadow.no-transform-expected.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.composite.shadow.no-transform-expected.html
new file mode 100644
index 0000000000..2b4436806a
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.composite.shadow.no-transform-expected.html
@@ -0,0 +1,78 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<title>Canvas test: 2d.layer.global-states.composite.shadow.no-transform</title>
+<h1 style="font-size: 20px;">2d.layer.global-states.composite.shadow.no-transform</h1>
+<p class="desc">Checks that layers correctly use global render states.</p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(2, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>no-globalAlpha</div>
+ <canvas id="canvas0" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas0");
+ const ctx = canvas.getContext('2d');
+
+ // No transform.
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ // No globalAlpha.
+ ctx.globalCompositeOperation = 'source-in';
+ ctx.shadowOffsetX = -7;
+ ctx.shadowOffsetY = 7;
+ ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
+ ctx.shadowBlur = 3;
+
+ const canvas2 = document.createElement("canvas");
+ const ctx2 = canvas2.getContext("2d");
+
+ ctx2.globalCompositeOperation = 'screen';
+ ctx2.fillStyle = 'rgba(255, 0, 0, 1)';
+ ctx2.fillRect(10, 25, 40, 50);
+ ctx2.fillStyle = 'rgba(0, 255, 0, 1)';
+ ctx2.fillRect(30, 5, 50, 40);
+
+ ctx.drawImage(canvas2, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>globalAlpha</div>
+ <canvas id="canvas1" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas1");
+ const ctx = canvas.getContext('2d');
+
+ // No transform.
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ ctx.globalAlpha = 0.75;
+ ctx.globalCompositeOperation = 'source-in';
+ ctx.shadowOffsetX = -7;
+ ctx.shadowOffsetY = 7;
+ ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
+ ctx.shadowBlur = 3;
+
+ const canvas2 = document.createElement("canvas");
+ const ctx2 = canvas2.getContext("2d");
+
+ ctx2.globalCompositeOperation = 'screen';
+ ctx2.fillStyle = 'rgba(255, 0, 0, 1)';
+ ctx2.fillRect(10, 25, 40, 50);
+ ctx2.fillStyle = 'rgba(0, 255, 0, 1)';
+ ctx2.fillRect(30, 5, 50, 40);
+
+ ctx.drawImage(canvas2, 0, 0);
+ </script>
+</span>
+
+</div>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.composite.shadow.no-transform.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.composite.shadow.no-transform.html
new file mode 100644
index 0000000000..8b79eba128
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.composite.shadow.no-transform.html
@@ -0,0 +1,91 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<link rel="match" href="2d.layer.global-states.composite.shadow.no-transform-expected.html">
+<title>Canvas test: 2d.layer.global-states.composite.shadow.no-transform</title>
+<h1 style="font-size: 20px;">2d.layer.global-states.composite.shadow.no-transform</h1>
+<p class="desc">Checks that layers correctly use global render states.</p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(2, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>no-globalAlpha</div>
+ <canvas id="canvas0" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(90, 90);
+ const ctx = canvas.getContext('2d');
+
+ // No transform.
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ // No globalAlpha.
+ ctx.globalCompositeOperation = 'source-in';
+ ctx.shadowOffsetX = -7;
+ ctx.shadowOffsetY = 7;
+ ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
+ ctx.shadowBlur = 3;
+
+ ctx.beginLayer();
+
+ // Enable compositing in the layer to validate that draw calls in the layer
+ // won't individually composite with the background.
+ ctx.globalCompositeOperation = 'screen';
+
+ 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();
+
+ const outputCanvas = document.getElementById("canvas0");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>globalAlpha</div>
+ <canvas id="canvas1" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(90, 90);
+ const ctx = canvas.getContext('2d');
+
+ // No transform.
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ ctx.globalAlpha = 0.75;
+ ctx.globalCompositeOperation = 'source-in';
+ ctx.shadowOffsetX = -7;
+ ctx.shadowOffsetY = 7;
+ ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
+ ctx.shadowBlur = 3;
+
+ ctx.beginLayer();
+
+ // Enable compositing in the layer to validate that draw calls in the layer
+ // won't individually composite with the background.
+ ctx.globalCompositeOperation = 'screen';
+
+ 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();
+
+ const outputCanvas = document.getElementById("canvas1");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+</div>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.composite.shadow.no-transform.w.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.composite.shadow.no-transform.w.html
new file mode 100644
index 0000000000..47f2df391f
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.composite.shadow.no-transform.w.html
@@ -0,0 +1,122 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<html class="reftest-wait">
+<link rel="match" href="2d.layer.global-states.composite.shadow.no-transform-expected.html">
+<title>Canvas test: 2d.layer.global-states.composite.shadow.no-transform</title>
+<h1 style="font-size: 20px;">2d.layer.global-states.composite.shadow.no-transform</h1>
+<p class="desc">Checks that layers correctly use global render states.</p>
+<script>pending_tests = 2;</script>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(2, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>no-globalAlpha</div>
+ <canvas id="canvas0" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script id="myWorker0" type="text/worker">
+ self.onmessage = function(e) {
+ const canvas = new OffscreenCanvas(90, 90);
+ const ctx = canvas.getContext('2d');
+
+ // No transform.
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ // No globalAlpha.
+ ctx.globalCompositeOperation = 'source-in';
+ ctx.shadowOffsetX = -7;
+ ctx.shadowOffsetY = 7;
+ ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
+ ctx.shadowBlur = 3;
+
+ ctx.beginLayer();
+
+ // Enable compositing in the layer to validate that draw calls in the layer
+ // won't individually composite with the background.
+ ctx.globalCompositeOperation = 'screen';
+
+ 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();
+
+ const bitmap = canvas.transferToImageBitmap();
+ self.postMessage(bitmap, bitmap);
+ };
+ </script>
+ <script type="module">
+ const blob = new Blob([document.getElementById('myWorker0').textContent]);
+ const worker = new Worker(URL.createObjectURL(blob));
+ worker.addEventListener('message', msg => {
+ const outputCanvas = document.getElementById('canvas0');
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(msg.data, 0, 0);
+ if (--pending_tests == 0) {
+ document.documentElement.classList.remove('reftest-wait');
+ }
+ });
+ worker.postMessage(null);
+ </script>
+</span>
+
+<span>
+ <div>globalAlpha</div>
+ <canvas id="canvas1" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script id="myWorker1" type="text/worker">
+ self.onmessage = function(e) {
+ const canvas = new OffscreenCanvas(90, 90);
+ const ctx = canvas.getContext('2d');
+
+ // No transform.
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ ctx.globalAlpha = 0.75;
+ ctx.globalCompositeOperation = 'source-in';
+ ctx.shadowOffsetX = -7;
+ ctx.shadowOffsetY = 7;
+ ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
+ ctx.shadowBlur = 3;
+
+ ctx.beginLayer();
+
+ // Enable compositing in the layer to validate that draw calls in the layer
+ // won't individually composite with the background.
+ ctx.globalCompositeOperation = 'screen';
+
+ 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();
+
+ const bitmap = canvas.transferToImageBitmap();
+ self.postMessage(bitmap, bitmap);
+ };
+ </script>
+ <script type="module">
+ const blob = new Blob([document.getElementById('myWorker1').textContent]);
+ const worker = new Worker(URL.createObjectURL(blob));
+ worker.addEventListener('message', msg => {
+ const outputCanvas = document.getElementById('canvas1');
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(msg.data, 0, 0);
+ if (--pending_tests == 0) {
+ document.documentElement.classList.remove('reftest-wait');
+ }
+ });
+ worker.postMessage(null);
+ </script>
+</span>
+
+</div>
+</html>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.composite.shadow.rotation-expected.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.composite.shadow.rotation-expected.html
new file mode 100644
index 0000000000..da144975a5
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.composite.shadow.rotation-expected.html
@@ -0,0 +1,82 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<title>Canvas test: 2d.layer.global-states.composite.shadow.rotation</title>
+<h1 style="font-size: 20px;">2d.layer.global-states.composite.shadow.rotation</h1>
+<p class="desc">Checks that layers correctly use global render states.</p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(2, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>no-globalAlpha</div>
+ <canvas id="canvas0" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas0");
+ const ctx = canvas.getContext('2d');
+
+ ctx.translate(50, 40);
+ ctx.rotate(Math.PI);
+ ctx.translate(-45, -45);
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ // No globalAlpha.
+ ctx.globalCompositeOperation = 'source-in';
+ ctx.shadowOffsetX = -7;
+ ctx.shadowOffsetY = 7;
+ ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
+ ctx.shadowBlur = 3;
+
+ const canvas2 = document.createElement("canvas");
+ const ctx2 = canvas2.getContext("2d");
+
+ ctx2.globalCompositeOperation = 'screen';
+ ctx2.fillStyle = 'rgba(255, 0, 0, 1)';
+ ctx2.fillRect(10, 25, 40, 50);
+ ctx2.fillStyle = 'rgba(0, 255, 0, 1)';
+ ctx2.fillRect(30, 5, 50, 40);
+
+ ctx.drawImage(canvas2, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>globalAlpha</div>
+ <canvas id="canvas1" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas1");
+ const ctx = canvas.getContext('2d');
+
+ ctx.translate(50, 40);
+ ctx.rotate(Math.PI);
+ ctx.translate(-45, -45);
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ ctx.globalAlpha = 0.75;
+ ctx.globalCompositeOperation = 'source-in';
+ ctx.shadowOffsetX = -7;
+ ctx.shadowOffsetY = 7;
+ ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
+ ctx.shadowBlur = 3;
+
+ const canvas2 = document.createElement("canvas");
+ const ctx2 = canvas2.getContext("2d");
+
+ ctx2.globalCompositeOperation = 'screen';
+ ctx2.fillStyle = 'rgba(255, 0, 0, 1)';
+ ctx2.fillRect(10, 25, 40, 50);
+ ctx2.fillStyle = 'rgba(0, 255, 0, 1)';
+ ctx2.fillRect(30, 5, 50, 40);
+
+ ctx.drawImage(canvas2, 0, 0);
+ </script>
+</span>
+
+</div>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.composite.shadow.rotation.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.composite.shadow.rotation.html
new file mode 100644
index 0000000000..632d390986
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.composite.shadow.rotation.html
@@ -0,0 +1,95 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<link rel="match" href="2d.layer.global-states.composite.shadow.rotation-expected.html">
+<title>Canvas test: 2d.layer.global-states.composite.shadow.rotation</title>
+<h1 style="font-size: 20px;">2d.layer.global-states.composite.shadow.rotation</h1>
+<p class="desc">Checks that layers correctly use global render states.</p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(2, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>no-globalAlpha</div>
+ <canvas id="canvas0" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(90, 90);
+ const ctx = canvas.getContext('2d');
+
+ ctx.translate(50, 40);
+ ctx.rotate(Math.PI);
+ ctx.translate(-45, -45);
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ // No globalAlpha.
+ ctx.globalCompositeOperation = 'source-in';
+ ctx.shadowOffsetX = -7;
+ ctx.shadowOffsetY = 7;
+ ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
+ ctx.shadowBlur = 3;
+
+ ctx.beginLayer();
+
+ // Enable compositing in the layer to validate that draw calls in the layer
+ // won't individually composite with the background.
+ ctx.globalCompositeOperation = 'screen';
+
+ 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();
+
+ const outputCanvas = document.getElementById("canvas0");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>globalAlpha</div>
+ <canvas id="canvas1" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(90, 90);
+ const ctx = canvas.getContext('2d');
+
+ ctx.translate(50, 40);
+ ctx.rotate(Math.PI);
+ ctx.translate(-45, -45);
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ ctx.globalAlpha = 0.75;
+ ctx.globalCompositeOperation = 'source-in';
+ ctx.shadowOffsetX = -7;
+ ctx.shadowOffsetY = 7;
+ ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
+ ctx.shadowBlur = 3;
+
+ ctx.beginLayer();
+
+ // Enable compositing in the layer to validate that draw calls in the layer
+ // won't individually composite with the background.
+ ctx.globalCompositeOperation = 'screen';
+
+ 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();
+
+ const outputCanvas = document.getElementById("canvas1");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+</div>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.composite.shadow.rotation.w.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.composite.shadow.rotation.w.html
new file mode 100644
index 0000000000..dde0d8bec0
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.composite.shadow.rotation.w.html
@@ -0,0 +1,126 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<html class="reftest-wait">
+<link rel="match" href="2d.layer.global-states.composite.shadow.rotation-expected.html">
+<title>Canvas test: 2d.layer.global-states.composite.shadow.rotation</title>
+<h1 style="font-size: 20px;">2d.layer.global-states.composite.shadow.rotation</h1>
+<p class="desc">Checks that layers correctly use global render states.</p>
+<script>pending_tests = 2;</script>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(2, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>no-globalAlpha</div>
+ <canvas id="canvas0" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script id="myWorker0" type="text/worker">
+ self.onmessage = function(e) {
+ const canvas = new OffscreenCanvas(90, 90);
+ const ctx = canvas.getContext('2d');
+
+ ctx.translate(50, 40);
+ ctx.rotate(Math.PI);
+ ctx.translate(-45, -45);
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ // No globalAlpha.
+ ctx.globalCompositeOperation = 'source-in';
+ ctx.shadowOffsetX = -7;
+ ctx.shadowOffsetY = 7;
+ ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
+ ctx.shadowBlur = 3;
+
+ ctx.beginLayer();
+
+ // Enable compositing in the layer to validate that draw calls in the layer
+ // won't individually composite with the background.
+ ctx.globalCompositeOperation = 'screen';
+
+ 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();
+
+ const bitmap = canvas.transferToImageBitmap();
+ self.postMessage(bitmap, bitmap);
+ };
+ </script>
+ <script type="module">
+ const blob = new Blob([document.getElementById('myWorker0').textContent]);
+ const worker = new Worker(URL.createObjectURL(blob));
+ worker.addEventListener('message', msg => {
+ const outputCanvas = document.getElementById('canvas0');
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(msg.data, 0, 0);
+ if (--pending_tests == 0) {
+ document.documentElement.classList.remove('reftest-wait');
+ }
+ });
+ worker.postMessage(null);
+ </script>
+</span>
+
+<span>
+ <div>globalAlpha</div>
+ <canvas id="canvas1" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script id="myWorker1" type="text/worker">
+ self.onmessage = function(e) {
+ const canvas = new OffscreenCanvas(90, 90);
+ const ctx = canvas.getContext('2d');
+
+ ctx.translate(50, 40);
+ ctx.rotate(Math.PI);
+ ctx.translate(-45, -45);
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ ctx.globalAlpha = 0.75;
+ ctx.globalCompositeOperation = 'source-in';
+ ctx.shadowOffsetX = -7;
+ ctx.shadowOffsetY = 7;
+ ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
+ ctx.shadowBlur = 3;
+
+ ctx.beginLayer();
+
+ // Enable compositing in the layer to validate that draw calls in the layer
+ // won't individually composite with the background.
+ ctx.globalCompositeOperation = 'screen';
+
+ 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();
+
+ const bitmap = canvas.transferToImageBitmap();
+ self.postMessage(bitmap, bitmap);
+ };
+ </script>
+ <script type="module">
+ const blob = new Blob([document.getElementById('myWorker1').textContent]);
+ const worker = new Worker(URL.createObjectURL(blob));
+ worker.addEventListener('message', msg => {
+ const outputCanvas = document.getElementById('canvas1');
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(msg.data, 0, 0);
+ if (--pending_tests == 0) {
+ document.documentElement.classList.remove('reftest-wait');
+ }
+ });
+ worker.postMessage(null);
+ </script>
+</span>
+
+</div>
+</html>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.composite.shadow.w.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.composite.shadow.w.html
deleted file mode 100644
index 7dfb70148b..0000000000
--- a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.composite.shadow.w.html
+++ /dev/null
@@ -1,55 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<html class="reftest-wait">
-<link rel="match" href="2d.layer.global-states.composite.shadow-expected.html">
-<title>Canvas test: 2d.layer.global-states.composite.shadow</title>
-<h1>2d.layer.global-states.composite.shadow</h1>
-<p class="desc">Checks that layers correctly use global render states.</p>
-<canvas id="canvas" width="200" height="200">
- <p class="fallback">FAIL (fallback content)</p>
-</canvas>
-<script id='myWorker' type='text/worker'>
- self.onmessage = function(e) {
- const canvas = new OffscreenCanvas(200, 200);
- const ctx = canvas.getContext('2d');
-
- ctx.fillStyle = 'rgba(0, 0, 255, 1)';
-
- var circle = new Path2D();
- circle.arc(90, 90, 45, 0, 2 * Math.PI);
- ctx.fill(circle);
-
- ctx.globalCompositeOperation = 'source-in';
- ctx.shadowOffsetX = -10;
- ctx.shadowOffsetY = 10;
- ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
- ctx.shadowBlur = 3;
-
- ctx.beginLayer();
-
- // Enable compositing in the layer to validate that draw calls in the layer
- // 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(0, 255, 0, 1)';
- ctx.fillRect(70, 70, 75, 50);
-
- ctx.endLayer();
-
- const bitmap = canvas.transferToImageBitmap();
- self.postMessage(bitmap, bitmap);
- };
-</script>
-<script>
- const blob = new Blob([document.getElementById('myWorker').textContent]);
- const worker = new Worker(URL.createObjectURL(blob));
- worker.addEventListener('message', msg => {
- const outputCtx = document.getElementById("canvas").getContext('2d');
- outputCtx.drawImage(msg.data, 0, 0);
- document.documentElement.classList.remove("reftest-wait");
- });
- worker.postMessage(null);
-</script>
-</html>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.composite.w.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.composite.w.html
deleted file mode 100644
index b695871fcd..0000000000
--- a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.composite.w.html
+++ /dev/null
@@ -1,51 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<html class="reftest-wait">
-<link rel="match" href="2d.layer.global-states.composite-expected.html">
-<title>Canvas test: 2d.layer.global-states.composite</title>
-<h1>2d.layer.global-states.composite</h1>
-<p class="desc">Checks that layers correctly use global render states.</p>
-<canvas id="canvas" width="200" height="200">
- <p class="fallback">FAIL (fallback content)</p>
-</canvas>
-<script id='myWorker' type='text/worker'>
- self.onmessage = function(e) {
- const canvas = new OffscreenCanvas(200, 200);
- const ctx = canvas.getContext('2d');
-
- ctx.fillStyle = 'rgba(0, 0, 255, 1)';
-
- var circle = new Path2D();
- circle.arc(90, 90, 45, 0, 2 * Math.PI);
- ctx.fill(circle);
-
- ctx.globalCompositeOperation = 'source-in';
-
- ctx.beginLayer();
-
- // Enable compositing in the layer to validate that draw calls in the layer
- // 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(0, 255, 0, 1)';
- ctx.fillRect(70, 70, 75, 50);
-
- ctx.endLayer();
-
- const bitmap = canvas.transferToImageBitmap();
- self.postMessage(bitmap, bitmap);
- };
-</script>
-<script>
- const blob = new Blob([document.getElementById('myWorker').textContent]);
- const worker = new Worker(URL.createObjectURL(blob));
- worker.addEventListener('message', msg => {
- const outputCtx = document.getElementById("canvas").getContext('2d');
- outputCtx.drawImage(msg.data, 0, 0);
- document.documentElement.classList.remove("reftest-wait");
- });
- worker.postMessage(null);
-</script>
-</html>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.copy.no-shadow.no-transform-expected.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.copy.no-shadow.no-transform-expected.html
new file mode 100644
index 0000000000..489d432282
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.copy.no-shadow.no-transform-expected.html
@@ -0,0 +1,72 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<title>Canvas test: 2d.layer.global-states.copy.no-shadow.no-transform</title>
+<h1 style="font-size: 20px;">2d.layer.global-states.copy.no-shadow.no-transform</h1>
+<p class="desc">Checks that layers correctly use global render states.</p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(2, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>no-globalAlpha</div>
+ <canvas id="canvas0" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas0");
+ const ctx = canvas.getContext('2d');
+
+ // No transform.
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ // No globalAlpha.
+ ctx.globalCompositeOperation = 'copy';
+ // No shadow.
+
+ const canvas2 = document.createElement("canvas");
+ const ctx2 = canvas2.getContext("2d");
+
+ ctx2.globalCompositeOperation = 'screen';
+ ctx2.fillStyle = 'rgba(255, 0, 0, 1)';
+ ctx2.fillRect(10, 25, 40, 50);
+ ctx2.fillStyle = 'rgba(0, 255, 0, 1)';
+ ctx2.fillRect(30, 5, 50, 40);
+
+ ctx.drawImage(canvas2, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>globalAlpha</div>
+ <canvas id="canvas1" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas1");
+ const ctx = canvas.getContext('2d');
+
+ // No transform.
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ ctx.globalAlpha = 0.75;
+ ctx.globalCompositeOperation = 'copy';
+ // No shadow.
+
+ const canvas2 = document.createElement("canvas");
+ const ctx2 = canvas2.getContext("2d");
+
+ ctx2.globalCompositeOperation = 'screen';
+ ctx2.fillStyle = 'rgba(255, 0, 0, 1)';
+ ctx2.fillRect(10, 25, 40, 50);
+ ctx2.fillStyle = 'rgba(0, 255, 0, 1)';
+ ctx2.fillRect(30, 5, 50, 40);
+
+ ctx.drawImage(canvas2, 0, 0);
+ </script>
+</span>
+
+</div>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.copy.no-shadow.no-transform.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.copy.no-shadow.no-transform.html
new file mode 100644
index 0000000000..70b659f52b
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.copy.no-shadow.no-transform.html
@@ -0,0 +1,85 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<link rel="match" href="2d.layer.global-states.copy.no-shadow.no-transform-expected.html">
+<title>Canvas test: 2d.layer.global-states.copy.no-shadow.no-transform</title>
+<h1 style="font-size: 20px;">2d.layer.global-states.copy.no-shadow.no-transform</h1>
+<p class="desc">Checks that layers correctly use global render states.</p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(2, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>no-globalAlpha</div>
+ <canvas id="canvas0" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(90, 90);
+ const ctx = canvas.getContext('2d');
+
+ // No transform.
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ // No globalAlpha.
+ ctx.globalCompositeOperation = 'copy';
+ // No shadow.
+
+ ctx.beginLayer();
+
+ // Enable compositing in the layer to validate that draw calls in the layer
+ // won't individually composite with the background.
+ ctx.globalCompositeOperation = 'screen';
+
+ 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();
+
+ const outputCanvas = document.getElementById("canvas0");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>globalAlpha</div>
+ <canvas id="canvas1" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(90, 90);
+ const ctx = canvas.getContext('2d');
+
+ // No transform.
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ ctx.globalAlpha = 0.75;
+ ctx.globalCompositeOperation = 'copy';
+ // No shadow.
+
+ ctx.beginLayer();
+
+ // Enable compositing in the layer to validate that draw calls in the layer
+ // won't individually composite with the background.
+ ctx.globalCompositeOperation = 'screen';
+
+ 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();
+
+ const outputCanvas = document.getElementById("canvas1");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+</div>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.copy.no-shadow.no-transform.w.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.copy.no-shadow.no-transform.w.html
new file mode 100644
index 0000000000..1db7f17a94
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.copy.no-shadow.no-transform.w.html
@@ -0,0 +1,116 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<html class="reftest-wait">
+<link rel="match" href="2d.layer.global-states.copy.no-shadow.no-transform-expected.html">
+<title>Canvas test: 2d.layer.global-states.copy.no-shadow.no-transform</title>
+<h1 style="font-size: 20px;">2d.layer.global-states.copy.no-shadow.no-transform</h1>
+<p class="desc">Checks that layers correctly use global render states.</p>
+<script>pending_tests = 2;</script>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(2, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>no-globalAlpha</div>
+ <canvas id="canvas0" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script id="myWorker0" type="text/worker">
+ self.onmessage = function(e) {
+ const canvas = new OffscreenCanvas(90, 90);
+ const ctx = canvas.getContext('2d');
+
+ // No transform.
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ // No globalAlpha.
+ ctx.globalCompositeOperation = 'copy';
+ // No shadow.
+
+ ctx.beginLayer();
+
+ // Enable compositing in the layer to validate that draw calls in the layer
+ // won't individually composite with the background.
+ ctx.globalCompositeOperation = 'screen';
+
+ 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();
+
+ const bitmap = canvas.transferToImageBitmap();
+ self.postMessage(bitmap, bitmap);
+ };
+ </script>
+ <script type="module">
+ const blob = new Blob([document.getElementById('myWorker0').textContent]);
+ const worker = new Worker(URL.createObjectURL(blob));
+ worker.addEventListener('message', msg => {
+ const outputCanvas = document.getElementById('canvas0');
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(msg.data, 0, 0);
+ if (--pending_tests == 0) {
+ document.documentElement.classList.remove('reftest-wait');
+ }
+ });
+ worker.postMessage(null);
+ </script>
+</span>
+
+<span>
+ <div>globalAlpha</div>
+ <canvas id="canvas1" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script id="myWorker1" type="text/worker">
+ self.onmessage = function(e) {
+ const canvas = new OffscreenCanvas(90, 90);
+ const ctx = canvas.getContext('2d');
+
+ // No transform.
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ ctx.globalAlpha = 0.75;
+ ctx.globalCompositeOperation = 'copy';
+ // No shadow.
+
+ ctx.beginLayer();
+
+ // Enable compositing in the layer to validate that draw calls in the layer
+ // won't individually composite with the background.
+ ctx.globalCompositeOperation = 'screen';
+
+ 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();
+
+ const bitmap = canvas.transferToImageBitmap();
+ self.postMessage(bitmap, bitmap);
+ };
+ </script>
+ <script type="module">
+ const blob = new Blob([document.getElementById('myWorker1').textContent]);
+ const worker = new Worker(URL.createObjectURL(blob));
+ worker.addEventListener('message', msg => {
+ const outputCanvas = document.getElementById('canvas1');
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(msg.data, 0, 0);
+ if (--pending_tests == 0) {
+ document.documentElement.classList.remove('reftest-wait');
+ }
+ });
+ worker.postMessage(null);
+ </script>
+</span>
+
+</div>
+</html>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.copy.no-shadow.rotation-expected.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.copy.no-shadow.rotation-expected.html
new file mode 100644
index 0000000000..63913ffb05
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.copy.no-shadow.rotation-expected.html
@@ -0,0 +1,76 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<title>Canvas test: 2d.layer.global-states.copy.no-shadow.rotation</title>
+<h1 style="font-size: 20px;">2d.layer.global-states.copy.no-shadow.rotation</h1>
+<p class="desc">Checks that layers correctly use global render states.</p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(2, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>no-globalAlpha</div>
+ <canvas id="canvas0" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas0");
+ const ctx = canvas.getContext('2d');
+
+ ctx.translate(50, 40);
+ ctx.rotate(Math.PI);
+ ctx.translate(-45, -45);
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ // No globalAlpha.
+ ctx.globalCompositeOperation = 'copy';
+ // No shadow.
+
+ const canvas2 = document.createElement("canvas");
+ const ctx2 = canvas2.getContext("2d");
+
+ ctx2.globalCompositeOperation = 'screen';
+ ctx2.fillStyle = 'rgba(255, 0, 0, 1)';
+ ctx2.fillRect(10, 25, 40, 50);
+ ctx2.fillStyle = 'rgba(0, 255, 0, 1)';
+ ctx2.fillRect(30, 5, 50, 40);
+
+ ctx.drawImage(canvas2, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>globalAlpha</div>
+ <canvas id="canvas1" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas1");
+ const ctx = canvas.getContext('2d');
+
+ ctx.translate(50, 40);
+ ctx.rotate(Math.PI);
+ ctx.translate(-45, -45);
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ ctx.globalAlpha = 0.75;
+ ctx.globalCompositeOperation = 'copy';
+ // No shadow.
+
+ const canvas2 = document.createElement("canvas");
+ const ctx2 = canvas2.getContext("2d");
+
+ ctx2.globalCompositeOperation = 'screen';
+ ctx2.fillStyle = 'rgba(255, 0, 0, 1)';
+ ctx2.fillRect(10, 25, 40, 50);
+ ctx2.fillStyle = 'rgba(0, 255, 0, 1)';
+ ctx2.fillRect(30, 5, 50, 40);
+
+ ctx.drawImage(canvas2, 0, 0);
+ </script>
+</span>
+
+</div>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.copy.no-shadow.rotation.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.copy.no-shadow.rotation.html
new file mode 100644
index 0000000000..2151535015
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.copy.no-shadow.rotation.html
@@ -0,0 +1,89 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<link rel="match" href="2d.layer.global-states.copy.no-shadow.rotation-expected.html">
+<title>Canvas test: 2d.layer.global-states.copy.no-shadow.rotation</title>
+<h1 style="font-size: 20px;">2d.layer.global-states.copy.no-shadow.rotation</h1>
+<p class="desc">Checks that layers correctly use global render states.</p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(2, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>no-globalAlpha</div>
+ <canvas id="canvas0" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(90, 90);
+ const ctx = canvas.getContext('2d');
+
+ ctx.translate(50, 40);
+ ctx.rotate(Math.PI);
+ ctx.translate(-45, -45);
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ // No globalAlpha.
+ ctx.globalCompositeOperation = 'copy';
+ // No shadow.
+
+ ctx.beginLayer();
+
+ // Enable compositing in the layer to validate that draw calls in the layer
+ // won't individually composite with the background.
+ ctx.globalCompositeOperation = 'screen';
+
+ 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();
+
+ const outputCanvas = document.getElementById("canvas0");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>globalAlpha</div>
+ <canvas id="canvas1" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(90, 90);
+ const ctx = canvas.getContext('2d');
+
+ ctx.translate(50, 40);
+ ctx.rotate(Math.PI);
+ ctx.translate(-45, -45);
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ ctx.globalAlpha = 0.75;
+ ctx.globalCompositeOperation = 'copy';
+ // No shadow.
+
+ ctx.beginLayer();
+
+ // Enable compositing in the layer to validate that draw calls in the layer
+ // won't individually composite with the background.
+ ctx.globalCompositeOperation = 'screen';
+
+ 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();
+
+ const outputCanvas = document.getElementById("canvas1");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+</div>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.copy.no-shadow.rotation.w.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.copy.no-shadow.rotation.w.html
new file mode 100644
index 0000000000..9c0cac99b9
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.copy.no-shadow.rotation.w.html
@@ -0,0 +1,120 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<html class="reftest-wait">
+<link rel="match" href="2d.layer.global-states.copy.no-shadow.rotation-expected.html">
+<title>Canvas test: 2d.layer.global-states.copy.no-shadow.rotation</title>
+<h1 style="font-size: 20px;">2d.layer.global-states.copy.no-shadow.rotation</h1>
+<p class="desc">Checks that layers correctly use global render states.</p>
+<script>pending_tests = 2;</script>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(2, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>no-globalAlpha</div>
+ <canvas id="canvas0" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script id="myWorker0" type="text/worker">
+ self.onmessage = function(e) {
+ const canvas = new OffscreenCanvas(90, 90);
+ const ctx = canvas.getContext('2d');
+
+ ctx.translate(50, 40);
+ ctx.rotate(Math.PI);
+ ctx.translate(-45, -45);
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ // No globalAlpha.
+ ctx.globalCompositeOperation = 'copy';
+ // No shadow.
+
+ ctx.beginLayer();
+
+ // Enable compositing in the layer to validate that draw calls in the layer
+ // won't individually composite with the background.
+ ctx.globalCompositeOperation = 'screen';
+
+ 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();
+
+ const bitmap = canvas.transferToImageBitmap();
+ self.postMessage(bitmap, bitmap);
+ };
+ </script>
+ <script type="module">
+ const blob = new Blob([document.getElementById('myWorker0').textContent]);
+ const worker = new Worker(URL.createObjectURL(blob));
+ worker.addEventListener('message', msg => {
+ const outputCanvas = document.getElementById('canvas0');
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(msg.data, 0, 0);
+ if (--pending_tests == 0) {
+ document.documentElement.classList.remove('reftest-wait');
+ }
+ });
+ worker.postMessage(null);
+ </script>
+</span>
+
+<span>
+ <div>globalAlpha</div>
+ <canvas id="canvas1" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script id="myWorker1" type="text/worker">
+ self.onmessage = function(e) {
+ const canvas = new OffscreenCanvas(90, 90);
+ const ctx = canvas.getContext('2d');
+
+ ctx.translate(50, 40);
+ ctx.rotate(Math.PI);
+ ctx.translate(-45, -45);
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ ctx.globalAlpha = 0.75;
+ ctx.globalCompositeOperation = 'copy';
+ // No shadow.
+
+ ctx.beginLayer();
+
+ // Enable compositing in the layer to validate that draw calls in the layer
+ // won't individually composite with the background.
+ ctx.globalCompositeOperation = 'screen';
+
+ 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();
+
+ const bitmap = canvas.transferToImageBitmap();
+ self.postMessage(bitmap, bitmap);
+ };
+ </script>
+ <script type="module">
+ const blob = new Blob([document.getElementById('myWorker1').textContent]);
+ const worker = new Worker(URL.createObjectURL(blob));
+ worker.addEventListener('message', msg => {
+ const outputCanvas = document.getElementById('canvas1');
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(msg.data, 0, 0);
+ if (--pending_tests == 0) {
+ document.documentElement.classList.remove('reftest-wait');
+ }
+ });
+ worker.postMessage(null);
+ </script>
+</span>
+
+</div>
+</html>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.copy.shadow.no-transform-expected.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.copy.shadow.no-transform-expected.html
new file mode 100644
index 0000000000..021581f892
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.copy.shadow.no-transform-expected.html
@@ -0,0 +1,78 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<title>Canvas test: 2d.layer.global-states.copy.shadow.no-transform</title>
+<h1 style="font-size: 20px;">2d.layer.global-states.copy.shadow.no-transform</h1>
+<p class="desc">Checks that layers correctly use global render states.</p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(2, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>no-globalAlpha</div>
+ <canvas id="canvas0" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas0");
+ const ctx = canvas.getContext('2d');
+
+ // No transform.
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ // No globalAlpha.
+ ctx.globalCompositeOperation = 'copy';
+ ctx.shadowOffsetX = -7;
+ ctx.shadowOffsetY = 7;
+ ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
+ ctx.shadowBlur = 3;
+
+ const canvas2 = document.createElement("canvas");
+ const ctx2 = canvas2.getContext("2d");
+
+ ctx2.globalCompositeOperation = 'screen';
+ ctx2.fillStyle = 'rgba(255, 0, 0, 1)';
+ ctx2.fillRect(10, 25, 40, 50);
+ ctx2.fillStyle = 'rgba(0, 255, 0, 1)';
+ ctx2.fillRect(30, 5, 50, 40);
+
+ ctx.drawImage(canvas2, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>globalAlpha</div>
+ <canvas id="canvas1" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas1");
+ const ctx = canvas.getContext('2d');
+
+ // No transform.
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ ctx.globalAlpha = 0.75;
+ ctx.globalCompositeOperation = 'copy';
+ ctx.shadowOffsetX = -7;
+ ctx.shadowOffsetY = 7;
+ ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
+ ctx.shadowBlur = 3;
+
+ const canvas2 = document.createElement("canvas");
+ const ctx2 = canvas2.getContext("2d");
+
+ ctx2.globalCompositeOperation = 'screen';
+ ctx2.fillStyle = 'rgba(255, 0, 0, 1)';
+ ctx2.fillRect(10, 25, 40, 50);
+ ctx2.fillStyle = 'rgba(0, 255, 0, 1)';
+ ctx2.fillRect(30, 5, 50, 40);
+
+ ctx.drawImage(canvas2, 0, 0);
+ </script>
+</span>
+
+</div>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.copy.shadow.no-transform.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.copy.shadow.no-transform.html
new file mode 100644
index 0000000000..42231fa61e
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.copy.shadow.no-transform.html
@@ -0,0 +1,91 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<link rel="match" href="2d.layer.global-states.copy.shadow.no-transform-expected.html">
+<title>Canvas test: 2d.layer.global-states.copy.shadow.no-transform</title>
+<h1 style="font-size: 20px;">2d.layer.global-states.copy.shadow.no-transform</h1>
+<p class="desc">Checks that layers correctly use global render states.</p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(2, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>no-globalAlpha</div>
+ <canvas id="canvas0" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(90, 90);
+ const ctx = canvas.getContext('2d');
+
+ // No transform.
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ // No globalAlpha.
+ ctx.globalCompositeOperation = 'copy';
+ ctx.shadowOffsetX = -7;
+ ctx.shadowOffsetY = 7;
+ ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
+ ctx.shadowBlur = 3;
+
+ ctx.beginLayer();
+
+ // Enable compositing in the layer to validate that draw calls in the layer
+ // won't individually composite with the background.
+ ctx.globalCompositeOperation = 'screen';
+
+ 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();
+
+ const outputCanvas = document.getElementById("canvas0");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>globalAlpha</div>
+ <canvas id="canvas1" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(90, 90);
+ const ctx = canvas.getContext('2d');
+
+ // No transform.
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ ctx.globalAlpha = 0.75;
+ ctx.globalCompositeOperation = 'copy';
+ ctx.shadowOffsetX = -7;
+ ctx.shadowOffsetY = 7;
+ ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
+ ctx.shadowBlur = 3;
+
+ ctx.beginLayer();
+
+ // Enable compositing in the layer to validate that draw calls in the layer
+ // won't individually composite with the background.
+ ctx.globalCompositeOperation = 'screen';
+
+ 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();
+
+ const outputCanvas = document.getElementById("canvas1");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+</div>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.copy.shadow.no-transform.w.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.copy.shadow.no-transform.w.html
new file mode 100644
index 0000000000..20dc667ef8
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.copy.shadow.no-transform.w.html
@@ -0,0 +1,122 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<html class="reftest-wait">
+<link rel="match" href="2d.layer.global-states.copy.shadow.no-transform-expected.html">
+<title>Canvas test: 2d.layer.global-states.copy.shadow.no-transform</title>
+<h1 style="font-size: 20px;">2d.layer.global-states.copy.shadow.no-transform</h1>
+<p class="desc">Checks that layers correctly use global render states.</p>
+<script>pending_tests = 2;</script>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(2, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>no-globalAlpha</div>
+ <canvas id="canvas0" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script id="myWorker0" type="text/worker">
+ self.onmessage = function(e) {
+ const canvas = new OffscreenCanvas(90, 90);
+ const ctx = canvas.getContext('2d');
+
+ // No transform.
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ // No globalAlpha.
+ ctx.globalCompositeOperation = 'copy';
+ ctx.shadowOffsetX = -7;
+ ctx.shadowOffsetY = 7;
+ ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
+ ctx.shadowBlur = 3;
+
+ ctx.beginLayer();
+
+ // Enable compositing in the layer to validate that draw calls in the layer
+ // won't individually composite with the background.
+ ctx.globalCompositeOperation = 'screen';
+
+ 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();
+
+ const bitmap = canvas.transferToImageBitmap();
+ self.postMessage(bitmap, bitmap);
+ };
+ </script>
+ <script type="module">
+ const blob = new Blob([document.getElementById('myWorker0').textContent]);
+ const worker = new Worker(URL.createObjectURL(blob));
+ worker.addEventListener('message', msg => {
+ const outputCanvas = document.getElementById('canvas0');
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(msg.data, 0, 0);
+ if (--pending_tests == 0) {
+ document.documentElement.classList.remove('reftest-wait');
+ }
+ });
+ worker.postMessage(null);
+ </script>
+</span>
+
+<span>
+ <div>globalAlpha</div>
+ <canvas id="canvas1" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script id="myWorker1" type="text/worker">
+ self.onmessage = function(e) {
+ const canvas = new OffscreenCanvas(90, 90);
+ const ctx = canvas.getContext('2d');
+
+ // No transform.
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ ctx.globalAlpha = 0.75;
+ ctx.globalCompositeOperation = 'copy';
+ ctx.shadowOffsetX = -7;
+ ctx.shadowOffsetY = 7;
+ ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
+ ctx.shadowBlur = 3;
+
+ ctx.beginLayer();
+
+ // Enable compositing in the layer to validate that draw calls in the layer
+ // won't individually composite with the background.
+ ctx.globalCompositeOperation = 'screen';
+
+ 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();
+
+ const bitmap = canvas.transferToImageBitmap();
+ self.postMessage(bitmap, bitmap);
+ };
+ </script>
+ <script type="module">
+ const blob = new Blob([document.getElementById('myWorker1').textContent]);
+ const worker = new Worker(URL.createObjectURL(blob));
+ worker.addEventListener('message', msg => {
+ const outputCanvas = document.getElementById('canvas1');
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(msg.data, 0, 0);
+ if (--pending_tests == 0) {
+ document.documentElement.classList.remove('reftest-wait');
+ }
+ });
+ worker.postMessage(null);
+ </script>
+</span>
+
+</div>
+</html>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.copy.shadow.rotation-expected.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.copy.shadow.rotation-expected.html
new file mode 100644
index 0000000000..dd9a5c2a00
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.copy.shadow.rotation-expected.html
@@ -0,0 +1,82 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<title>Canvas test: 2d.layer.global-states.copy.shadow.rotation</title>
+<h1 style="font-size: 20px;">2d.layer.global-states.copy.shadow.rotation</h1>
+<p class="desc">Checks that layers correctly use global render states.</p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(2, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>no-globalAlpha</div>
+ <canvas id="canvas0" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas0");
+ const ctx = canvas.getContext('2d');
+
+ ctx.translate(50, 40);
+ ctx.rotate(Math.PI);
+ ctx.translate(-45, -45);
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ // No globalAlpha.
+ ctx.globalCompositeOperation = 'copy';
+ ctx.shadowOffsetX = -7;
+ ctx.shadowOffsetY = 7;
+ ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
+ ctx.shadowBlur = 3;
+
+ const canvas2 = document.createElement("canvas");
+ const ctx2 = canvas2.getContext("2d");
+
+ ctx2.globalCompositeOperation = 'screen';
+ ctx2.fillStyle = 'rgba(255, 0, 0, 1)';
+ ctx2.fillRect(10, 25, 40, 50);
+ ctx2.fillStyle = 'rgba(0, 255, 0, 1)';
+ ctx2.fillRect(30, 5, 50, 40);
+
+ ctx.drawImage(canvas2, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>globalAlpha</div>
+ <canvas id="canvas1" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas1");
+ const ctx = canvas.getContext('2d');
+
+ ctx.translate(50, 40);
+ ctx.rotate(Math.PI);
+ ctx.translate(-45, -45);
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ ctx.globalAlpha = 0.75;
+ ctx.globalCompositeOperation = 'copy';
+ ctx.shadowOffsetX = -7;
+ ctx.shadowOffsetY = 7;
+ ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
+ ctx.shadowBlur = 3;
+
+ const canvas2 = document.createElement("canvas");
+ const ctx2 = canvas2.getContext("2d");
+
+ ctx2.globalCompositeOperation = 'screen';
+ ctx2.fillStyle = 'rgba(255, 0, 0, 1)';
+ ctx2.fillRect(10, 25, 40, 50);
+ ctx2.fillStyle = 'rgba(0, 255, 0, 1)';
+ ctx2.fillRect(30, 5, 50, 40);
+
+ ctx.drawImage(canvas2, 0, 0);
+ </script>
+</span>
+
+</div>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.copy.shadow.rotation.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.copy.shadow.rotation.html
new file mode 100644
index 0000000000..77158a9f96
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.copy.shadow.rotation.html
@@ -0,0 +1,95 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<link rel="match" href="2d.layer.global-states.copy.shadow.rotation-expected.html">
+<title>Canvas test: 2d.layer.global-states.copy.shadow.rotation</title>
+<h1 style="font-size: 20px;">2d.layer.global-states.copy.shadow.rotation</h1>
+<p class="desc">Checks that layers correctly use global render states.</p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(2, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>no-globalAlpha</div>
+ <canvas id="canvas0" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(90, 90);
+ const ctx = canvas.getContext('2d');
+
+ ctx.translate(50, 40);
+ ctx.rotate(Math.PI);
+ ctx.translate(-45, -45);
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ // No globalAlpha.
+ ctx.globalCompositeOperation = 'copy';
+ ctx.shadowOffsetX = -7;
+ ctx.shadowOffsetY = 7;
+ ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
+ ctx.shadowBlur = 3;
+
+ ctx.beginLayer();
+
+ // Enable compositing in the layer to validate that draw calls in the layer
+ // won't individually composite with the background.
+ ctx.globalCompositeOperation = 'screen';
+
+ 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();
+
+ const outputCanvas = document.getElementById("canvas0");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>globalAlpha</div>
+ <canvas id="canvas1" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(90, 90);
+ const ctx = canvas.getContext('2d');
+
+ ctx.translate(50, 40);
+ ctx.rotate(Math.PI);
+ ctx.translate(-45, -45);
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ ctx.globalAlpha = 0.75;
+ ctx.globalCompositeOperation = 'copy';
+ ctx.shadowOffsetX = -7;
+ ctx.shadowOffsetY = 7;
+ ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
+ ctx.shadowBlur = 3;
+
+ ctx.beginLayer();
+
+ // Enable compositing in the layer to validate that draw calls in the layer
+ // won't individually composite with the background.
+ ctx.globalCompositeOperation = 'screen';
+
+ 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();
+
+ const outputCanvas = document.getElementById("canvas1");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+</div>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.copy.shadow.rotation.w.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.copy.shadow.rotation.w.html
new file mode 100644
index 0000000000..def6bc51e2
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.copy.shadow.rotation.w.html
@@ -0,0 +1,126 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<html class="reftest-wait">
+<link rel="match" href="2d.layer.global-states.copy.shadow.rotation-expected.html">
+<title>Canvas test: 2d.layer.global-states.copy.shadow.rotation</title>
+<h1 style="font-size: 20px;">2d.layer.global-states.copy.shadow.rotation</h1>
+<p class="desc">Checks that layers correctly use global render states.</p>
+<script>pending_tests = 2;</script>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(2, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>no-globalAlpha</div>
+ <canvas id="canvas0" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script id="myWorker0" type="text/worker">
+ self.onmessage = function(e) {
+ const canvas = new OffscreenCanvas(90, 90);
+ const ctx = canvas.getContext('2d');
+
+ ctx.translate(50, 40);
+ ctx.rotate(Math.PI);
+ ctx.translate(-45, -45);
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ // No globalAlpha.
+ ctx.globalCompositeOperation = 'copy';
+ ctx.shadowOffsetX = -7;
+ ctx.shadowOffsetY = 7;
+ ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
+ ctx.shadowBlur = 3;
+
+ ctx.beginLayer();
+
+ // Enable compositing in the layer to validate that draw calls in the layer
+ // won't individually composite with the background.
+ ctx.globalCompositeOperation = 'screen';
+
+ 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();
+
+ const bitmap = canvas.transferToImageBitmap();
+ self.postMessage(bitmap, bitmap);
+ };
+ </script>
+ <script type="module">
+ const blob = new Blob([document.getElementById('myWorker0').textContent]);
+ const worker = new Worker(URL.createObjectURL(blob));
+ worker.addEventListener('message', msg => {
+ const outputCanvas = document.getElementById('canvas0');
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(msg.data, 0, 0);
+ if (--pending_tests == 0) {
+ document.documentElement.classList.remove('reftest-wait');
+ }
+ });
+ worker.postMessage(null);
+ </script>
+</span>
+
+<span>
+ <div>globalAlpha</div>
+ <canvas id="canvas1" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script id="myWorker1" type="text/worker">
+ self.onmessage = function(e) {
+ const canvas = new OffscreenCanvas(90, 90);
+ const ctx = canvas.getContext('2d');
+
+ ctx.translate(50, 40);
+ ctx.rotate(Math.PI);
+ ctx.translate(-45, -45);
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ ctx.globalAlpha = 0.75;
+ ctx.globalCompositeOperation = 'copy';
+ ctx.shadowOffsetX = -7;
+ ctx.shadowOffsetY = 7;
+ ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
+ ctx.shadowBlur = 3;
+
+ ctx.beginLayer();
+
+ // Enable compositing in the layer to validate that draw calls in the layer
+ // won't individually composite with the background.
+ ctx.globalCompositeOperation = 'screen';
+
+ 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();
+
+ const bitmap = canvas.transferToImageBitmap();
+ self.postMessage(bitmap, bitmap);
+ };
+ </script>
+ <script type="module">
+ const blob = new Blob([document.getElementById('myWorker1').textContent]);
+ const worker = new Worker(URL.createObjectURL(blob));
+ worker.addEventListener('message', msg => {
+ const outputCanvas = document.getElementById('canvas1');
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(msg.data, 0, 0);
+ if (--pending_tests == 0) {
+ document.documentElement.classList.remove('reftest-wait');
+ }
+ });
+ worker.postMessage(null);
+ </script>
+</span>
+
+</div>
+</html>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.alpha-expected.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.alpha-expected.html
deleted file mode 100644
index f304700feb..0000000000
--- a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.alpha-expected.html
+++ /dev/null
@@ -1,50 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<title>Canvas test: 2d.layer.global-states.filter.alpha</title>
-<h1>2d.layer.global-states.filter.alpha</h1>
-<p class="desc">Checks that layers with filters correctly use global render states.</p>
-<canvas id="canvas" width="200" height="200">
- <p class="fallback">FAIL (fallback content)</p>
-</canvas>
-<script>
- const canvas = document.getElementById("canvas");
- const ctx = canvas.getContext('2d');
-
- const svg = `
- <svg xmlns="http://www.w3.org/2000/svg"
- width="200" height="200"
- 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" />
- <feComponentTransfer>
- <feFuncA type="table" tableValues="0 0.7"></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)"/>
- </g>
- </svg>`;
-
- const img = new Image();
- img.width = 200;
- img.height = 200;
- img.onload = () => {
- ctx.fillStyle = 'rgba(0, 0, 255, 1)';
-
- var circle = new Path2D();
- circle.arc(90, 90, 45, 0, 2 * Math.PI);
- ctx.fill(circle);
-
- ctx.globalAlpha = 0.6;
-
- ctx.drawImage(img, 0, 0);
- };
- img.src = 'data:image/svg+xml;base64,' + btoa(svg);
-</script>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.alpha.blending-expected.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.alpha.blending-expected.html
deleted file mode 100644
index 7c91ce4229..0000000000
--- a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.alpha.blending-expected.html
+++ /dev/null
@@ -1,51 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<title>Canvas test: 2d.layer.global-states.filter.alpha.blending</title>
-<h1>2d.layer.global-states.filter.alpha.blending</h1>
-<p class="desc">Checks that layers with filters correctly use global render states.</p>
-<canvas id="canvas" width="200" height="200">
- <p class="fallback">FAIL (fallback content)</p>
-</canvas>
-<script>
- const canvas = document.getElementById("canvas");
- const ctx = canvas.getContext('2d');
-
- const svg = `
- <svg xmlns="http://www.w3.org/2000/svg"
- width="200" height="200"
- 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" />
- <feComponentTransfer>
- <feFuncA type="table" tableValues="0 0.7"></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)"/>
- </g>
- </svg>`;
-
- const img = new Image();
- img.width = 200;
- img.height = 200;
- img.onload = () => {
- ctx.fillStyle = 'rgba(0, 0, 255, 1)';
-
- var circle = new Path2D();
- circle.arc(90, 90, 45, 0, 2 * Math.PI);
- ctx.fill(circle);
-
- ctx.globalAlpha = 0.6;
- ctx.globalCompositeOperation = 'multiply';
-
- ctx.drawImage(img, 0, 0);
- };
- img.src = 'data:image/svg+xml;base64,' + btoa(svg);
-</script>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.alpha.blending.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.alpha.blending.html
deleted file mode 100644
index 0e48cb49f7..0000000000
--- a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.alpha.blending.html
+++ /dev/null
@@ -1,42 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<link rel="match" href="2d.layer.global-states.filter.alpha.blending-expected.html">
-<meta name=fuzzy content="maxDifference=0-1; totalPixels=0-2453">
-<title>Canvas test: 2d.layer.global-states.filter.alpha.blending</title>
-<h1>2d.layer.global-states.filter.alpha.blending</h1>
-<p class="desc">Checks that layers with filters correctly use global render states.</p>
-<canvas id="canvas" width="200" height="200">
- <p class="fallback">FAIL (fallback content)</p>
-</canvas>
-<script>
- const canvas = new OffscreenCanvas(200, 200);
- const ctx = canvas.getContext('2d');
-
- ctx.fillStyle = 'rgba(0, 0, 255, 1)';
-
- var circle = new Path2D();
- circle.arc(90, 90, 45, 0, 2 * Math.PI);
- ctx.fill(circle);
-
- ctx.globalAlpha = 0.6;
- ctx.globalCompositeOperation = 'multiply';
-
- 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: 'componentTransfer',
- funcA: {type: "table", tableValues: [0, 0.7]}},
- {name: 'dropShadow', dx: 5, dy: 5, floodColor: '#81e'}]});
-
- 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.endLayer();
-
- const outputCanvas = document.getElementById("canvas");
- outputCanvas.getContext('2d').drawImage(canvas, 0, 0);
-</script>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.alpha.blending.shadow-expected.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.alpha.blending.shadow-expected.html
deleted file mode 100644
index 62942ffeae..0000000000
--- a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.alpha.blending.shadow-expected.html
+++ /dev/null
@@ -1,55 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<title>Canvas test: 2d.layer.global-states.filter.alpha.blending.shadow</title>
-<h1>2d.layer.global-states.filter.alpha.blending.shadow</h1>
-<p class="desc">Checks that layers with filters correctly use global render states.</p>
-<canvas id="canvas" width="200" height="200">
- <p class="fallback">FAIL (fallback content)</p>
-</canvas>
-<script>
- const canvas = document.getElementById("canvas");
- const ctx = canvas.getContext('2d');
-
- const svg = `
- <svg xmlns="http://www.w3.org/2000/svg"
- width="200" height="200"
- 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" />
- <feComponentTransfer>
- <feFuncA type="table" tableValues="0 0.7"></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)"/>
- </g>
- </svg>`;
-
- const img = new Image();
- img.width = 200;
- img.height = 200;
- img.onload = () => {
- ctx.fillStyle = 'rgba(0, 0, 255, 1)';
-
- var circle = new Path2D();
- circle.arc(90, 90, 45, 0, 2 * Math.PI);
- ctx.fill(circle);
-
- ctx.globalAlpha = 0.6;
- ctx.globalCompositeOperation = 'multiply';
- ctx.shadowOffsetX = -10;
- ctx.shadowOffsetY = 10;
- ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
- ctx.shadowBlur = 3;
-
- ctx.drawImage(img, 0, 0);
- };
- img.src = 'data:image/svg+xml;base64,' + btoa(svg);
-</script>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.alpha.blending.shadow.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.alpha.blending.shadow.html
deleted file mode 100644
index 62d98d967c..0000000000
--- a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.alpha.blending.shadow.html
+++ /dev/null
@@ -1,45 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<link rel="match" href="2d.layer.global-states.filter.alpha.blending.shadow-expected.html">
-<title>Canvas test: 2d.layer.global-states.filter.alpha.blending.shadow</title>
-<h1>2d.layer.global-states.filter.alpha.blending.shadow</h1>
-<p class="desc">Checks that layers with filters correctly use global render states.</p>
-<canvas id="canvas" width="200" height="200">
- <p class="fallback">FAIL (fallback content)</p>
-</canvas>
-<script>
- const canvas = new OffscreenCanvas(200, 200);
- const ctx = canvas.getContext('2d');
-
- ctx.fillStyle = 'rgba(0, 0, 255, 1)';
-
- var circle = new Path2D();
- circle.arc(90, 90, 45, 0, 2 * Math.PI);
- ctx.fill(circle);
-
- ctx.globalAlpha = 0.6;
- ctx.globalCompositeOperation = 'multiply';
- ctx.shadowOffsetX = -10;
- ctx.shadowOffsetY = 10;
- ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
- ctx.shadowBlur = 3;
-
- 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: 'componentTransfer',
- funcA: {type: "table", tableValues: [0, 0.7]}},
- {name: 'dropShadow', dx: 5, dy: 5, floodColor: '#81e'}]});
-
- 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.endLayer();
-
- const outputCanvas = document.getElementById("canvas");
- outputCanvas.getContext('2d').drawImage(canvas, 0, 0);
-</script>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.alpha.blending.shadow.w.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.alpha.blending.shadow.w.html
deleted file mode 100644
index e81efd6b8d..0000000000
--- a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.alpha.blending.shadow.w.html
+++ /dev/null
@@ -1,59 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<html class="reftest-wait">
-<link rel="match" href="2d.layer.global-states.filter.alpha.blending.shadow-expected.html">
-<title>Canvas test: 2d.layer.global-states.filter.alpha.blending.shadow</title>
-<h1>2d.layer.global-states.filter.alpha.blending.shadow</h1>
-<p class="desc">Checks that layers with filters correctly use global render states.</p>
-<canvas id="canvas" width="200" height="200">
- <p class="fallback">FAIL (fallback content)</p>
-</canvas>
-<script id='myWorker' type='text/worker'>
- self.onmessage = function(e) {
- const canvas = new OffscreenCanvas(200, 200);
- const ctx = canvas.getContext('2d');
-
- ctx.fillStyle = 'rgba(0, 0, 255, 1)';
-
- var circle = new Path2D();
- circle.arc(90, 90, 45, 0, 2 * Math.PI);
- ctx.fill(circle);
-
- ctx.globalAlpha = 0.6;
- ctx.globalCompositeOperation = 'multiply';
- ctx.shadowOffsetX = -10;
- ctx.shadowOffsetY = 10;
- ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
- ctx.shadowBlur = 3;
-
- 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: 'componentTransfer',
- funcA: {type: "table", tableValues: [0, 0.7]}},
- {name: 'dropShadow', dx: 5, dy: 5, floodColor: '#81e'}]});
-
- 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.endLayer();
-
- const bitmap = canvas.transferToImageBitmap();
- self.postMessage(bitmap, bitmap);
- };
-</script>
-<script>
- const blob = new Blob([document.getElementById('myWorker').textContent]);
- const worker = new Worker(URL.createObjectURL(blob));
- worker.addEventListener('message', msg => {
- const outputCtx = document.getElementById("canvas").getContext('2d');
- outputCtx.drawImage(msg.data, 0, 0);
- document.documentElement.classList.remove("reftest-wait");
- });
- worker.postMessage(null);
-</script>
-</html>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.alpha.blending.w.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.alpha.blending.w.html
deleted file mode 100644
index 3887ed4485..0000000000
--- a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.alpha.blending.w.html
+++ /dev/null
@@ -1,56 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<html class="reftest-wait">
-<link rel="match" href="2d.layer.global-states.filter.alpha.blending-expected.html">
-<meta name=fuzzy content="maxDifference=0-1; totalPixels=0-2453">
-<title>Canvas test: 2d.layer.global-states.filter.alpha.blending</title>
-<h1>2d.layer.global-states.filter.alpha.blending</h1>
-<p class="desc">Checks that layers with filters correctly use global render states.</p>
-<canvas id="canvas" width="200" height="200">
- <p class="fallback">FAIL (fallback content)</p>
-</canvas>
-<script id='myWorker' type='text/worker'>
- self.onmessage = function(e) {
- const canvas = new OffscreenCanvas(200, 200);
- const ctx = canvas.getContext('2d');
-
- ctx.fillStyle = 'rgba(0, 0, 255, 1)';
-
- var circle = new Path2D();
- circle.arc(90, 90, 45, 0, 2 * Math.PI);
- ctx.fill(circle);
-
- ctx.globalAlpha = 0.6;
- ctx.globalCompositeOperation = 'multiply';
-
- 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: 'componentTransfer',
- funcA: {type: "table", tableValues: [0, 0.7]}},
- {name: 'dropShadow', dx: 5, dy: 5, floodColor: '#81e'}]});
-
- 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.endLayer();
-
- const bitmap = canvas.transferToImageBitmap();
- self.postMessage(bitmap, bitmap);
- };
-</script>
-<script>
- const blob = new Blob([document.getElementById('myWorker').textContent]);
- const worker = new Worker(URL.createObjectURL(blob));
- worker.addEventListener('message', msg => {
- const outputCtx = document.getElementById("canvas").getContext('2d');
- outputCtx.drawImage(msg.data, 0, 0);
- document.documentElement.classList.remove("reftest-wait");
- });
- worker.postMessage(null);
-</script>
-</html>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.alpha.composite-expected.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.alpha.composite-expected.html
deleted file mode 100644
index 8e0d98648e..0000000000
--- a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.alpha.composite-expected.html
+++ /dev/null
@@ -1,51 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<title>Canvas test: 2d.layer.global-states.filter.alpha.composite</title>
-<h1>2d.layer.global-states.filter.alpha.composite</h1>
-<p class="desc">Checks that layers with filters correctly use global render states.</p>
-<canvas id="canvas" width="200" height="200">
- <p class="fallback">FAIL (fallback content)</p>
-</canvas>
-<script>
- const canvas = document.getElementById("canvas");
- const ctx = canvas.getContext('2d');
-
- const svg = `
- <svg xmlns="http://www.w3.org/2000/svg"
- width="200" height="200"
- 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" />
- <feComponentTransfer>
- <feFuncA type="table" tableValues="0 0.7"></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)"/>
- </g>
- </svg>`;
-
- const img = new Image();
- img.width = 200;
- img.height = 200;
- img.onload = () => {
- ctx.fillStyle = 'rgba(0, 0, 255, 1)';
-
- var circle = new Path2D();
- circle.arc(90, 90, 45, 0, 2 * Math.PI);
- ctx.fill(circle);
-
- ctx.globalAlpha = 0.6;
- ctx.globalCompositeOperation = 'source-in';
-
- ctx.drawImage(img, 0, 0);
- };
- img.src = 'data:image/svg+xml;base64,' + btoa(svg);
-</script>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.alpha.composite.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.alpha.composite.html
deleted file mode 100644
index 1a9bc8b733..0000000000
--- a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.alpha.composite.html
+++ /dev/null
@@ -1,42 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<link rel="match" href="2d.layer.global-states.filter.alpha.composite-expected.html">
-<meta name=fuzzy content="maxDifference=0-1; totalPixels=0-5204">
-<title>Canvas test: 2d.layer.global-states.filter.alpha.composite</title>
-<h1>2d.layer.global-states.filter.alpha.composite</h1>
-<p class="desc">Checks that layers with filters correctly use global render states.</p>
-<canvas id="canvas" width="200" height="200">
- <p class="fallback">FAIL (fallback content)</p>
-</canvas>
-<script>
- const canvas = new OffscreenCanvas(200, 200);
- const ctx = canvas.getContext('2d');
-
- ctx.fillStyle = 'rgba(0, 0, 255, 1)';
-
- var circle = new Path2D();
- circle.arc(90, 90, 45, 0, 2 * Math.PI);
- ctx.fill(circle);
-
- ctx.globalAlpha = 0.6;
- ctx.globalCompositeOperation = 'source-in';
-
- 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: 'componentTransfer',
- funcA: {type: "table", tableValues: [0, 0.7]}},
- {name: 'dropShadow', dx: 5, dy: 5, floodColor: '#81e'}]});
-
- 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.endLayer();
-
- const outputCanvas = document.getElementById("canvas");
- outputCanvas.getContext('2d').drawImage(canvas, 0, 0);
-</script>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.alpha.composite.shadow-expected.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.alpha.composite.shadow-expected.html
deleted file mode 100644
index a649972546..0000000000
--- a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.alpha.composite.shadow-expected.html
+++ /dev/null
@@ -1,55 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<title>Canvas test: 2d.layer.global-states.filter.alpha.composite.shadow</title>
-<h1>2d.layer.global-states.filter.alpha.composite.shadow</h1>
-<p class="desc">Checks that layers with filters correctly use global render states.</p>
-<canvas id="canvas" width="200" height="200">
- <p class="fallback">FAIL (fallback content)</p>
-</canvas>
-<script>
- const canvas = document.getElementById("canvas");
- const ctx = canvas.getContext('2d');
-
- const svg = `
- <svg xmlns="http://www.w3.org/2000/svg"
- width="200" height="200"
- 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" />
- <feComponentTransfer>
- <feFuncA type="table" tableValues="0 0.7"></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)"/>
- </g>
- </svg>`;
-
- const img = new Image();
- img.width = 200;
- img.height = 200;
- img.onload = () => {
- ctx.fillStyle = 'rgba(0, 0, 255, 1)';
-
- var circle = new Path2D();
- circle.arc(90, 90, 45, 0, 2 * Math.PI);
- ctx.fill(circle);
-
- 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;
-
- ctx.drawImage(img, 0, 0);
- };
- img.src = 'data:image/svg+xml;base64,' + btoa(svg);
-</script>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.alpha.composite.shadow.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.alpha.composite.shadow.html
deleted file mode 100644
index d067ff2f5e..0000000000
--- a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.alpha.composite.shadow.html
+++ /dev/null
@@ -1,45 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<link rel="match" href="2d.layer.global-states.filter.alpha.composite.shadow-expected.html">
-<title>Canvas test: 2d.layer.global-states.filter.alpha.composite.shadow</title>
-<h1>2d.layer.global-states.filter.alpha.composite.shadow</h1>
-<p class="desc">Checks that layers with filters correctly use global render states.</p>
-<canvas id="canvas" width="200" height="200">
- <p class="fallback">FAIL (fallback content)</p>
-</canvas>
-<script>
- const canvas = new OffscreenCanvas(200, 200);
- const ctx = canvas.getContext('2d');
-
- ctx.fillStyle = 'rgba(0, 0, 255, 1)';
-
- var circle = new Path2D();
- circle.arc(90, 90, 45, 0, 2 * Math.PI);
- ctx.fill(circle);
-
- 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;
-
- 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: 'componentTransfer',
- funcA: {type: "table", tableValues: [0, 0.7]}},
- {name: 'dropShadow', dx: 5, dy: 5, floodColor: '#81e'}]});
-
- 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.endLayer();
-
- const outputCanvas = document.getElementById("canvas");
- outputCanvas.getContext('2d').drawImage(canvas, 0, 0);
-</script>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.alpha.composite.shadow.w.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.alpha.composite.shadow.w.html
deleted file mode 100644
index 39abc78b17..0000000000
--- a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.alpha.composite.shadow.w.html
+++ /dev/null
@@ -1,59 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<html class="reftest-wait">
-<link rel="match" href="2d.layer.global-states.filter.alpha.composite.shadow-expected.html">
-<title>Canvas test: 2d.layer.global-states.filter.alpha.composite.shadow</title>
-<h1>2d.layer.global-states.filter.alpha.composite.shadow</h1>
-<p class="desc">Checks that layers with filters correctly use global render states.</p>
-<canvas id="canvas" width="200" height="200">
- <p class="fallback">FAIL (fallback content)</p>
-</canvas>
-<script id='myWorker' type='text/worker'>
- self.onmessage = function(e) {
- const canvas = new OffscreenCanvas(200, 200);
- const ctx = canvas.getContext('2d');
-
- ctx.fillStyle = 'rgba(0, 0, 255, 1)';
-
- var circle = new Path2D();
- circle.arc(90, 90, 45, 0, 2 * Math.PI);
- ctx.fill(circle);
-
- 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;
-
- 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: 'componentTransfer',
- funcA: {type: "table", tableValues: [0, 0.7]}},
- {name: 'dropShadow', dx: 5, dy: 5, floodColor: '#81e'}]});
-
- 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.endLayer();
-
- const bitmap = canvas.transferToImageBitmap();
- self.postMessage(bitmap, bitmap);
- };
-</script>
-<script>
- const blob = new Blob([document.getElementById('myWorker').textContent]);
- const worker = new Worker(URL.createObjectURL(blob));
- worker.addEventListener('message', msg => {
- const outputCtx = document.getElementById("canvas").getContext('2d');
- outputCtx.drawImage(msg.data, 0, 0);
- document.documentElement.classList.remove("reftest-wait");
- });
- worker.postMessage(null);
-</script>
-</html>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.alpha.composite.w.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.alpha.composite.w.html
deleted file mode 100644
index 5c90fe95aa..0000000000
--- a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.alpha.composite.w.html
+++ /dev/null
@@ -1,56 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<html class="reftest-wait">
-<link rel="match" href="2d.layer.global-states.filter.alpha.composite-expected.html">
-<meta name=fuzzy content="maxDifference=0-1; totalPixels=0-5204">
-<title>Canvas test: 2d.layer.global-states.filter.alpha.composite</title>
-<h1>2d.layer.global-states.filter.alpha.composite</h1>
-<p class="desc">Checks that layers with filters correctly use global render states.</p>
-<canvas id="canvas" width="200" height="200">
- <p class="fallback">FAIL (fallback content)</p>
-</canvas>
-<script id='myWorker' type='text/worker'>
- self.onmessage = function(e) {
- const canvas = new OffscreenCanvas(200, 200);
- const ctx = canvas.getContext('2d');
-
- ctx.fillStyle = 'rgba(0, 0, 255, 1)';
-
- var circle = new Path2D();
- circle.arc(90, 90, 45, 0, 2 * Math.PI);
- ctx.fill(circle);
-
- ctx.globalAlpha = 0.6;
- ctx.globalCompositeOperation = 'source-in';
-
- 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: 'componentTransfer',
- funcA: {type: "table", tableValues: [0, 0.7]}},
- {name: 'dropShadow', dx: 5, dy: 5, floodColor: '#81e'}]});
-
- 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.endLayer();
-
- const bitmap = canvas.transferToImageBitmap();
- self.postMessage(bitmap, bitmap);
- };
-</script>
-<script>
- const blob = new Blob([document.getElementById('myWorker').textContent]);
- const worker = new Worker(URL.createObjectURL(blob));
- worker.addEventListener('message', msg => {
- const outputCtx = document.getElementById("canvas").getContext('2d');
- outputCtx.drawImage(msg.data, 0, 0);
- document.documentElement.classList.remove("reftest-wait");
- });
- worker.postMessage(null);
-</script>
-</html>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.alpha.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.alpha.html
deleted file mode 100644
index f64e8925f0..0000000000
--- a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.alpha.html
+++ /dev/null
@@ -1,41 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<link rel="match" href="2d.layer.global-states.filter.alpha-expected.html">
-<meta name=fuzzy content="maxDifference=0-2; totalPixels=0-6766">
-<title>Canvas test: 2d.layer.global-states.filter.alpha</title>
-<h1>2d.layer.global-states.filter.alpha</h1>
-<p class="desc">Checks that layers with filters correctly use global render states.</p>
-<canvas id="canvas" width="200" height="200">
- <p class="fallback">FAIL (fallback content)</p>
-</canvas>
-<script>
- const canvas = new OffscreenCanvas(200, 200);
- const ctx = canvas.getContext('2d');
-
- ctx.fillStyle = 'rgba(0, 0, 255, 1)';
-
- var circle = new Path2D();
- circle.arc(90, 90, 45, 0, 2 * Math.PI);
- ctx.fill(circle);
-
- ctx.globalAlpha = 0.6;
-
- 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: 'componentTransfer',
- funcA: {type: "table", tableValues: [0, 0.7]}},
- {name: 'dropShadow', dx: 5, dy: 5, floodColor: '#81e'}]});
-
- 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.endLayer();
-
- const outputCanvas = document.getElementById("canvas");
- outputCanvas.getContext('2d').drawImage(canvas, 0, 0);
-</script>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.alpha.shadow-expected.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.alpha.shadow-expected.html
deleted file mode 100644
index 169baee29b..0000000000
--- a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.alpha.shadow-expected.html
+++ /dev/null
@@ -1,54 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<title>Canvas test: 2d.layer.global-states.filter.alpha.shadow</title>
-<h1>2d.layer.global-states.filter.alpha.shadow</h1>
-<p class="desc">Checks that layers with filters correctly use global render states.</p>
-<canvas id="canvas" width="200" height="200">
- <p class="fallback">FAIL (fallback content)</p>
-</canvas>
-<script>
- const canvas = document.getElementById("canvas");
- const ctx = canvas.getContext('2d');
-
- const svg = `
- <svg xmlns="http://www.w3.org/2000/svg"
- width="200" height="200"
- 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" />
- <feComponentTransfer>
- <feFuncA type="table" tableValues="0 0.7"></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)"/>
- </g>
- </svg>`;
-
- const img = new Image();
- img.width = 200;
- img.height = 200;
- img.onload = () => {
- ctx.fillStyle = 'rgba(0, 0, 255, 1)';
-
- var circle = new Path2D();
- circle.arc(90, 90, 45, 0, 2 * Math.PI);
- ctx.fill(circle);
-
- ctx.globalAlpha = 0.5;
- ctx.shadowOffsetX = -10;
- ctx.shadowOffsetY = 10;
- ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
- ctx.shadowBlur = 3;
-
- ctx.drawImage(img, 0, 0);
- };
- img.src = 'data:image/svg+xml;base64,' + btoa(svg);
-</script>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.alpha.shadow.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.alpha.shadow.html
deleted file mode 100644
index 5e8911ee17..0000000000
--- a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.alpha.shadow.html
+++ /dev/null
@@ -1,45 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<link rel="match" href="2d.layer.global-states.filter.alpha.shadow-expected.html">
-<meta name=fuzzy content="maxDifference=0-2; totalPixels=0-6311">
-<title>Canvas test: 2d.layer.global-states.filter.alpha.shadow</title>
-<h1>2d.layer.global-states.filter.alpha.shadow</h1>
-<p class="desc">Checks that layers with filters correctly use global render states.</p>
-<canvas id="canvas" width="200" height="200">
- <p class="fallback">FAIL (fallback content)</p>
-</canvas>
-<script>
- const canvas = new OffscreenCanvas(200, 200);
- const ctx = canvas.getContext('2d');
-
- ctx.fillStyle = 'rgba(0, 0, 255, 1)';
-
- var circle = new Path2D();
- circle.arc(90, 90, 45, 0, 2 * Math.PI);
- ctx.fill(circle);
-
- ctx.globalAlpha = 0.5;
- ctx.shadowOffsetX = -10;
- ctx.shadowOffsetY = 10;
- ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
- ctx.shadowBlur = 3;
-
- 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: 'componentTransfer',
- funcA: {type: "table", tableValues: [0, 0.7]}},
- {name: 'dropShadow', dx: 5, dy: 5, floodColor: '#81e'}]});
-
- 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.endLayer();
-
- const outputCanvas = document.getElementById("canvas");
- outputCanvas.getContext('2d').drawImage(canvas, 0, 0);
-</script>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.alpha.shadow.w.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.alpha.shadow.w.html
deleted file mode 100644
index b3be7e1ac8..0000000000
--- a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.alpha.shadow.w.html
+++ /dev/null
@@ -1,59 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<html class="reftest-wait">
-<link rel="match" href="2d.layer.global-states.filter.alpha.shadow-expected.html">
-<meta name=fuzzy content="maxDifference=0-2; totalPixels=0-6311">
-<title>Canvas test: 2d.layer.global-states.filter.alpha.shadow</title>
-<h1>2d.layer.global-states.filter.alpha.shadow</h1>
-<p class="desc">Checks that layers with filters correctly use global render states.</p>
-<canvas id="canvas" width="200" height="200">
- <p class="fallback">FAIL (fallback content)</p>
-</canvas>
-<script id='myWorker' type='text/worker'>
- self.onmessage = function(e) {
- const canvas = new OffscreenCanvas(200, 200);
- const ctx = canvas.getContext('2d');
-
- ctx.fillStyle = 'rgba(0, 0, 255, 1)';
-
- var circle = new Path2D();
- circle.arc(90, 90, 45, 0, 2 * Math.PI);
- ctx.fill(circle);
-
- ctx.globalAlpha = 0.5;
- ctx.shadowOffsetX = -10;
- ctx.shadowOffsetY = 10;
- ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
- ctx.shadowBlur = 3;
-
- 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: 'componentTransfer',
- funcA: {type: "table", tableValues: [0, 0.7]}},
- {name: 'dropShadow', dx: 5, dy: 5, floodColor: '#81e'}]});
-
- 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.endLayer();
-
- const bitmap = canvas.transferToImageBitmap();
- self.postMessage(bitmap, bitmap);
- };
-</script>
-<script>
- const blob = new Blob([document.getElementById('myWorker').textContent]);
- const worker = new Worker(URL.createObjectURL(blob));
- worker.addEventListener('message', msg => {
- const outputCtx = document.getElementById("canvas").getContext('2d');
- outputCtx.drawImage(msg.data, 0, 0);
- document.documentElement.classList.remove("reftest-wait");
- });
- worker.postMessage(null);
-</script>
-</html>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.alpha.w.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.alpha.w.html
deleted file mode 100644
index 21e55f856c..0000000000
--- a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.alpha.w.html
+++ /dev/null
@@ -1,55 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<html class="reftest-wait">
-<link rel="match" href="2d.layer.global-states.filter.alpha-expected.html">
-<meta name=fuzzy content="maxDifference=0-2; totalPixels=0-6766">
-<title>Canvas test: 2d.layer.global-states.filter.alpha</title>
-<h1>2d.layer.global-states.filter.alpha</h1>
-<p class="desc">Checks that layers with filters correctly use global render states.</p>
-<canvas id="canvas" width="200" height="200">
- <p class="fallback">FAIL (fallback content)</p>
-</canvas>
-<script id='myWorker' type='text/worker'>
- self.onmessage = function(e) {
- const canvas = new OffscreenCanvas(200, 200);
- const ctx = canvas.getContext('2d');
-
- ctx.fillStyle = 'rgba(0, 0, 255, 1)';
-
- var circle = new Path2D();
- circle.arc(90, 90, 45, 0, 2 * Math.PI);
- ctx.fill(circle);
-
- ctx.globalAlpha = 0.6;
-
- 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: 'componentTransfer',
- funcA: {type: "table", tableValues: [0, 0.7]}},
- {name: 'dropShadow', dx: 5, dy: 5, floodColor: '#81e'}]});
-
- 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.endLayer();
-
- const bitmap = canvas.transferToImageBitmap();
- self.postMessage(bitmap, bitmap);
- };
-</script>
-<script>
- const blob = new Blob([document.getElementById('myWorker').textContent]);
- const worker = new Worker(URL.createObjectURL(blob));
- worker.addEventListener('message', msg => {
- const outputCtx = document.getElementById("canvas").getContext('2d');
- outputCtx.drawImage(msg.data, 0, 0);
- document.documentElement.classList.remove("reftest-wait");
- });
- worker.postMessage(null);
-</script>
-</html>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.blending-expected.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.blending-expected.html
deleted file mode 100644
index f81dcf72dc..0000000000
--- a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.blending-expected.html
+++ /dev/null
@@ -1,50 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<title>Canvas test: 2d.layer.global-states.filter.blending</title>
-<h1>2d.layer.global-states.filter.blending</h1>
-<p class="desc">Checks that layers with filters correctly use global render states.</p>
-<canvas id="canvas" width="200" height="200">
- <p class="fallback">FAIL (fallback content)</p>
-</canvas>
-<script>
- const canvas = document.getElementById("canvas");
- const ctx = canvas.getContext('2d');
-
- const svg = `
- <svg xmlns="http://www.w3.org/2000/svg"
- width="200" height="200"
- 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" />
- <feComponentTransfer>
- <feFuncA type="table" tableValues="0 0.7"></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)"/>
- </g>
- </svg>`;
-
- const img = new Image();
- img.width = 200;
- img.height = 200;
- img.onload = () => {
- ctx.fillStyle = 'rgba(0, 0, 255, 1)';
-
- var circle = new Path2D();
- circle.arc(90, 90, 45, 0, 2 * Math.PI);
- ctx.fill(circle);
-
- ctx.globalCompositeOperation = 'multiply';
-
- ctx.drawImage(img, 0, 0);
- };
- img.src = 'data:image/svg+xml;base64,' + btoa(svg);
-</script>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.blending.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.blending.html
deleted file mode 100644
index ce2b046798..0000000000
--- a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.blending.html
+++ /dev/null
@@ -1,40 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<link rel="match" href="2d.layer.global-states.filter.blending-expected.html">
-<title>Canvas test: 2d.layer.global-states.filter.blending</title>
-<h1>2d.layer.global-states.filter.blending</h1>
-<p class="desc">Checks that layers with filters correctly use global render states.</p>
-<canvas id="canvas" width="200" height="200">
- <p class="fallback">FAIL (fallback content)</p>
-</canvas>
-<script>
- const canvas = new OffscreenCanvas(200, 200);
- const ctx = canvas.getContext('2d');
-
- ctx.fillStyle = 'rgba(0, 0, 255, 1)';
-
- var circle = new Path2D();
- circle.arc(90, 90, 45, 0, 2 * Math.PI);
- ctx.fill(circle);
-
- ctx.globalCompositeOperation = 'multiply';
-
- 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: 'componentTransfer',
- funcA: {type: "table", tableValues: [0, 0.7]}},
- {name: 'dropShadow', dx: 5, dy: 5, floodColor: '#81e'}]});
-
- 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.endLayer();
-
- const outputCanvas = document.getElementById("canvas");
- outputCanvas.getContext('2d').drawImage(canvas, 0, 0);
-</script>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.blending.no-shadow.no-transform-expected.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.blending.no-shadow.no-transform-expected.html
new file mode 100644
index 0000000000..482ab25a85
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.blending.no-shadow.no-transform-expected.html
@@ -0,0 +1,98 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<title>Canvas test: 2d.layer.global-states.filter.blending.no-shadow.no-transform</title>
+<h1 style="font-size: 20px;">2d.layer.global-states.filter.blending.no-shadow.no-transform</h1>
+<p class="desc">Checks that layers with filters correctly use global render states.</p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(2, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>no-globalAlpha</div>
+ <canvas id="canvas0" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas0");
+ const ctx = canvas.getContext('2d');
+
+ const svg = `
+ <svg xmlns="http://www.w3.org/2000/svg"
+ width="90" height="90"
+ color-interpolation-filters="sRGB">
+ <filter id="filter" x="-100%" y="-100%" width="300%" height="300%">
+ <feDropShadow dx="5" dy="5" stdDeviation="0" flood-color="#00f" />
+ <feComponentTransfer>
+ <feFuncA type="table" tableValues="0 0.8"></feFuncA>
+ </feComponentTransfer>
+ </filter>
+ <g filter="url(#filter)">
+ <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>`;
+
+ const img = new Image();
+ img.width = 90;
+ img.height = 90;
+ img.onload = () => {
+ // No transform.
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ // No globalAlpha.
+ ctx.globalCompositeOperation = 'multiply';
+ // No shadow.
+
+ ctx.drawImage(img, 0, 0);
+ };
+ img.src = 'data:image/svg+xml;base64,' + btoa(svg);
+ </script>
+</span>
+
+<span>
+ <div>globalAlpha</div>
+ <canvas id="canvas1" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas1");
+ const ctx = canvas.getContext('2d');
+
+ const svg = `
+ <svg xmlns="http://www.w3.org/2000/svg"
+ width="90" height="90"
+ color-interpolation-filters="sRGB">
+ <filter id="filter" x="-100%" y="-100%" width="300%" height="300%">
+ <feDropShadow dx="5" dy="5" stdDeviation="0" flood-color="#00f" />
+ <feComponentTransfer>
+ <feFuncA type="table" tableValues="0 0.8"></feFuncA>
+ </feComponentTransfer>
+ </filter>
+ <g filter="url(#filter)">
+ <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>`;
+
+ const img = new Image();
+ img.width = 90;
+ img.height = 90;
+ img.onload = () => {
+ // No transform.
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ ctx.globalAlpha = 0.75;
+ ctx.globalCompositeOperation = 'multiply';
+ // No shadow.
+
+ ctx.drawImage(img, 0, 0);
+ };
+ img.src = 'data:image/svg+xml;base64,' + btoa(svg);
+ </script>
+</span>
+
+</div>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.blending.no-shadow.no-transform.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.blending.no-shadow.no-transform.html
new file mode 100644
index 0000000000..8acbfa668f
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.blending.no-shadow.no-transform.html
@@ -0,0 +1,85 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<link rel="match" href="2d.layer.global-states.filter.blending.no-shadow.no-transform-expected.html">
+<title>Canvas test: 2d.layer.global-states.filter.blending.no-shadow.no-transform</title>
+<h1 style="font-size: 20px;">2d.layer.global-states.filter.blending.no-shadow.no-transform</h1>
+<p class="desc">Checks that layers with filters correctly use global render states.</p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(2, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>no-globalAlpha</div>
+ <canvas id="canvas0" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(90, 90);
+ const ctx = canvas.getContext('2d');
+
+ // No transform.
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ // No globalAlpha.
+ ctx.globalCompositeOperation = 'multiply';
+ // No shadow.
+
+ ctx.beginLayer({filter: [
+ {name: 'dropShadow',
+ dx: 5, dy: 5, stdDeviation: 0, floodColor: '#00f'},
+ {name: 'componentTransfer',
+ funcA: {type: "table", tableValues: [0, 0.8]}}]});
+
+ 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();
+
+ const outputCanvas = document.getElementById("canvas0");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>globalAlpha</div>
+ <canvas id="canvas1" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(90, 90);
+ const ctx = canvas.getContext('2d');
+
+ // No transform.
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ ctx.globalAlpha = 0.75;
+ ctx.globalCompositeOperation = 'multiply';
+ // No shadow.
+
+ ctx.beginLayer({filter: [
+ {name: 'dropShadow',
+ dx: 5, dy: 5, stdDeviation: 0, floodColor: '#00f'},
+ {name: 'componentTransfer',
+ funcA: {type: "table", tableValues: [0, 0.8]}}]});
+
+ 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();
+
+ const outputCanvas = document.getElementById("canvas1");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+</div>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.blending.no-shadow.no-transform.w.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.blending.no-shadow.no-transform.w.html
new file mode 100644
index 0000000000..93edfabdf3
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.blending.no-shadow.no-transform.w.html
@@ -0,0 +1,116 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<html class="reftest-wait">
+<link rel="match" href="2d.layer.global-states.filter.blending.no-shadow.no-transform-expected.html">
+<title>Canvas test: 2d.layer.global-states.filter.blending.no-shadow.no-transform</title>
+<h1 style="font-size: 20px;">2d.layer.global-states.filter.blending.no-shadow.no-transform</h1>
+<p class="desc">Checks that layers with filters correctly use global render states.</p>
+<script>pending_tests = 2;</script>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(2, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>no-globalAlpha</div>
+ <canvas id="canvas0" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script id="myWorker0" type="text/worker">
+ self.onmessage = function(e) {
+ const canvas = new OffscreenCanvas(90, 90);
+ const ctx = canvas.getContext('2d');
+
+ // No transform.
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ // No globalAlpha.
+ ctx.globalCompositeOperation = 'multiply';
+ // No shadow.
+
+ ctx.beginLayer({filter: [
+ {name: 'dropShadow',
+ dx: 5, dy: 5, stdDeviation: 0, floodColor: '#00f'},
+ {name: 'componentTransfer',
+ funcA: {type: "table", tableValues: [0, 0.8]}}]});
+
+ 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();
+
+ const bitmap = canvas.transferToImageBitmap();
+ self.postMessage(bitmap, bitmap);
+ };
+ </script>
+ <script type="module">
+ const blob = new Blob([document.getElementById('myWorker0').textContent]);
+ const worker = new Worker(URL.createObjectURL(blob));
+ worker.addEventListener('message', msg => {
+ const outputCanvas = document.getElementById('canvas0');
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(msg.data, 0, 0);
+ if (--pending_tests == 0) {
+ document.documentElement.classList.remove('reftest-wait');
+ }
+ });
+ worker.postMessage(null);
+ </script>
+</span>
+
+<span>
+ <div>globalAlpha</div>
+ <canvas id="canvas1" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script id="myWorker1" type="text/worker">
+ self.onmessage = function(e) {
+ const canvas = new OffscreenCanvas(90, 90);
+ const ctx = canvas.getContext('2d');
+
+ // No transform.
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ ctx.globalAlpha = 0.75;
+ ctx.globalCompositeOperation = 'multiply';
+ // No shadow.
+
+ ctx.beginLayer({filter: [
+ {name: 'dropShadow',
+ dx: 5, dy: 5, stdDeviation: 0, floodColor: '#00f'},
+ {name: 'componentTransfer',
+ funcA: {type: "table", tableValues: [0, 0.8]}}]});
+
+ 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();
+
+ const bitmap = canvas.transferToImageBitmap();
+ self.postMessage(bitmap, bitmap);
+ };
+ </script>
+ <script type="module">
+ const blob = new Blob([document.getElementById('myWorker1').textContent]);
+ const worker = new Worker(URL.createObjectURL(blob));
+ worker.addEventListener('message', msg => {
+ const outputCanvas = document.getElementById('canvas1');
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(msg.data, 0, 0);
+ if (--pending_tests == 0) {
+ document.documentElement.classList.remove('reftest-wait');
+ }
+ });
+ worker.postMessage(null);
+ </script>
+</span>
+
+</div>
+</html>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.blending.no-shadow.rotation-expected.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.blending.no-shadow.rotation-expected.html
new file mode 100644
index 0000000000..3af6b863ed
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.blending.no-shadow.rotation-expected.html
@@ -0,0 +1,102 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<title>Canvas test: 2d.layer.global-states.filter.blending.no-shadow.rotation</title>
+<h1 style="font-size: 20px;">2d.layer.global-states.filter.blending.no-shadow.rotation</h1>
+<p class="desc">Checks that layers with filters correctly use global render states.</p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(2, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>no-globalAlpha</div>
+ <canvas id="canvas0" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas0");
+ const ctx = canvas.getContext('2d');
+
+ const svg = `
+ <svg xmlns="http://www.w3.org/2000/svg"
+ width="90" height="90"
+ color-interpolation-filters="sRGB">
+ <filter id="filter" x="-100%" y="-100%" width="300%" height="300%">
+ <feDropShadow dx="5" dy="5" stdDeviation="0" flood-color="#00f" />
+ <feComponentTransfer>
+ <feFuncA type="table" tableValues="0 0.8"></feFuncA>
+ </feComponentTransfer>
+ </filter>
+ <g filter="url(#filter)">
+ <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>`;
+
+ const img = new Image();
+ img.width = 90;
+ img.height = 90;
+ img.onload = () => {
+ ctx.translate(50, 40);
+ ctx.rotate(Math.PI);
+ ctx.translate(-45, -45);
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ // No globalAlpha.
+ ctx.globalCompositeOperation = 'multiply';
+ // No shadow.
+
+ ctx.drawImage(img, 0, 0);
+ };
+ img.src = 'data:image/svg+xml;base64,' + btoa(svg);
+ </script>
+</span>
+
+<span>
+ <div>globalAlpha</div>
+ <canvas id="canvas1" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas1");
+ const ctx = canvas.getContext('2d');
+
+ const svg = `
+ <svg xmlns="http://www.w3.org/2000/svg"
+ width="90" height="90"
+ color-interpolation-filters="sRGB">
+ <filter id="filter" x="-100%" y="-100%" width="300%" height="300%">
+ <feDropShadow dx="5" dy="5" stdDeviation="0" flood-color="#00f" />
+ <feComponentTransfer>
+ <feFuncA type="table" tableValues="0 0.8"></feFuncA>
+ </feComponentTransfer>
+ </filter>
+ <g filter="url(#filter)">
+ <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>`;
+
+ const img = new Image();
+ img.width = 90;
+ img.height = 90;
+ img.onload = () => {
+ ctx.translate(50, 40);
+ ctx.rotate(Math.PI);
+ ctx.translate(-45, -45);
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ ctx.globalAlpha = 0.75;
+ ctx.globalCompositeOperation = 'multiply';
+ // No shadow.
+
+ ctx.drawImage(img, 0, 0);
+ };
+ img.src = 'data:image/svg+xml;base64,' + btoa(svg);
+ </script>
+</span>
+
+</div>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.blending.no-shadow.rotation.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.blending.no-shadow.rotation.html
new file mode 100644
index 0000000000..0a4a8c65d2
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.blending.no-shadow.rotation.html
@@ -0,0 +1,89 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<link rel="match" href="2d.layer.global-states.filter.blending.no-shadow.rotation-expected.html">
+<title>Canvas test: 2d.layer.global-states.filter.blending.no-shadow.rotation</title>
+<h1 style="font-size: 20px;">2d.layer.global-states.filter.blending.no-shadow.rotation</h1>
+<p class="desc">Checks that layers with filters correctly use global render states.</p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(2, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>no-globalAlpha</div>
+ <canvas id="canvas0" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(90, 90);
+ const ctx = canvas.getContext('2d');
+
+ ctx.translate(50, 40);
+ ctx.rotate(Math.PI);
+ ctx.translate(-45, -45);
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ // No globalAlpha.
+ ctx.globalCompositeOperation = 'multiply';
+ // No shadow.
+
+ ctx.beginLayer({filter: [
+ {name: 'dropShadow',
+ dx: 5, dy: 5, stdDeviation: 0, floodColor: '#00f'},
+ {name: 'componentTransfer',
+ funcA: {type: "table", tableValues: [0, 0.8]}}]});
+
+ 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();
+
+ const outputCanvas = document.getElementById("canvas0");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>globalAlpha</div>
+ <canvas id="canvas1" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(90, 90);
+ const ctx = canvas.getContext('2d');
+
+ ctx.translate(50, 40);
+ ctx.rotate(Math.PI);
+ ctx.translate(-45, -45);
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ ctx.globalAlpha = 0.75;
+ ctx.globalCompositeOperation = 'multiply';
+ // No shadow.
+
+ ctx.beginLayer({filter: [
+ {name: 'dropShadow',
+ dx: 5, dy: 5, stdDeviation: 0, floodColor: '#00f'},
+ {name: 'componentTransfer',
+ funcA: {type: "table", tableValues: [0, 0.8]}}]});
+
+ 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();
+
+ const outputCanvas = document.getElementById("canvas1");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+</div>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.blending.no-shadow.rotation.w.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.blending.no-shadow.rotation.w.html
new file mode 100644
index 0000000000..7caaf1edee
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.blending.no-shadow.rotation.w.html
@@ -0,0 +1,120 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<html class="reftest-wait">
+<link rel="match" href="2d.layer.global-states.filter.blending.no-shadow.rotation-expected.html">
+<title>Canvas test: 2d.layer.global-states.filter.blending.no-shadow.rotation</title>
+<h1 style="font-size: 20px;">2d.layer.global-states.filter.blending.no-shadow.rotation</h1>
+<p class="desc">Checks that layers with filters correctly use global render states.</p>
+<script>pending_tests = 2;</script>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(2, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>no-globalAlpha</div>
+ <canvas id="canvas0" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script id="myWorker0" type="text/worker">
+ self.onmessage = function(e) {
+ const canvas = new OffscreenCanvas(90, 90);
+ const ctx = canvas.getContext('2d');
+
+ ctx.translate(50, 40);
+ ctx.rotate(Math.PI);
+ ctx.translate(-45, -45);
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ // No globalAlpha.
+ ctx.globalCompositeOperation = 'multiply';
+ // No shadow.
+
+ ctx.beginLayer({filter: [
+ {name: 'dropShadow',
+ dx: 5, dy: 5, stdDeviation: 0, floodColor: '#00f'},
+ {name: 'componentTransfer',
+ funcA: {type: "table", tableValues: [0, 0.8]}}]});
+
+ 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();
+
+ const bitmap = canvas.transferToImageBitmap();
+ self.postMessage(bitmap, bitmap);
+ };
+ </script>
+ <script type="module">
+ const blob = new Blob([document.getElementById('myWorker0').textContent]);
+ const worker = new Worker(URL.createObjectURL(blob));
+ worker.addEventListener('message', msg => {
+ const outputCanvas = document.getElementById('canvas0');
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(msg.data, 0, 0);
+ if (--pending_tests == 0) {
+ document.documentElement.classList.remove('reftest-wait');
+ }
+ });
+ worker.postMessage(null);
+ </script>
+</span>
+
+<span>
+ <div>globalAlpha</div>
+ <canvas id="canvas1" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script id="myWorker1" type="text/worker">
+ self.onmessage = function(e) {
+ const canvas = new OffscreenCanvas(90, 90);
+ const ctx = canvas.getContext('2d');
+
+ ctx.translate(50, 40);
+ ctx.rotate(Math.PI);
+ ctx.translate(-45, -45);
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ ctx.globalAlpha = 0.75;
+ ctx.globalCompositeOperation = 'multiply';
+ // No shadow.
+
+ ctx.beginLayer({filter: [
+ {name: 'dropShadow',
+ dx: 5, dy: 5, stdDeviation: 0, floodColor: '#00f'},
+ {name: 'componentTransfer',
+ funcA: {type: "table", tableValues: [0, 0.8]}}]});
+
+ 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();
+
+ const bitmap = canvas.transferToImageBitmap();
+ self.postMessage(bitmap, bitmap);
+ };
+ </script>
+ <script type="module">
+ const blob = new Blob([document.getElementById('myWorker1').textContent]);
+ const worker = new Worker(URL.createObjectURL(blob));
+ worker.addEventListener('message', msg => {
+ const outputCanvas = document.getElementById('canvas1');
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(msg.data, 0, 0);
+ if (--pending_tests == 0) {
+ document.documentElement.classList.remove('reftest-wait');
+ }
+ });
+ worker.postMessage(null);
+ </script>
+</span>
+
+</div>
+</html>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.blending.shadow-expected.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.blending.shadow-expected.html
deleted file mode 100644
index 91f3725f8e..0000000000
--- a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.blending.shadow-expected.html
+++ /dev/null
@@ -1,54 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<title>Canvas test: 2d.layer.global-states.filter.blending.shadow</title>
-<h1>2d.layer.global-states.filter.blending.shadow</h1>
-<p class="desc">Checks that layers with filters correctly use global render states.</p>
-<canvas id="canvas" width="200" height="200">
- <p class="fallback">FAIL (fallback content)</p>
-</canvas>
-<script>
- const canvas = document.getElementById("canvas");
- const ctx = canvas.getContext('2d');
-
- const svg = `
- <svg xmlns="http://www.w3.org/2000/svg"
- width="200" height="200"
- 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" />
- <feComponentTransfer>
- <feFuncA type="table" tableValues="0 0.7"></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)"/>
- </g>
- </svg>`;
-
- const img = new Image();
- img.width = 200;
- img.height = 200;
- img.onload = () => {
- ctx.fillStyle = 'rgba(0, 0, 255, 1)';
-
- var circle = new Path2D();
- circle.arc(90, 90, 45, 0, 2 * Math.PI);
- ctx.fill(circle);
-
- ctx.globalCompositeOperation = 'multiply';
- ctx.shadowOffsetX = -10;
- ctx.shadowOffsetY = 10;
- ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
- ctx.shadowBlur = 3;
-
- ctx.drawImage(img, 0, 0);
- };
- img.src = 'data:image/svg+xml;base64,' + btoa(svg);
-</script>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.blending.shadow.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.blending.shadow.html
deleted file mode 100644
index d0d429bee3..0000000000
--- a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.blending.shadow.html
+++ /dev/null
@@ -1,44 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<link rel="match" href="2d.layer.global-states.filter.blending.shadow-expected.html">
-<title>Canvas test: 2d.layer.global-states.filter.blending.shadow</title>
-<h1>2d.layer.global-states.filter.blending.shadow</h1>
-<p class="desc">Checks that layers with filters correctly use global render states.</p>
-<canvas id="canvas" width="200" height="200">
- <p class="fallback">FAIL (fallback content)</p>
-</canvas>
-<script>
- const canvas = new OffscreenCanvas(200, 200);
- const ctx = canvas.getContext('2d');
-
- ctx.fillStyle = 'rgba(0, 0, 255, 1)';
-
- var circle = new Path2D();
- circle.arc(90, 90, 45, 0, 2 * Math.PI);
- ctx.fill(circle);
-
- ctx.globalCompositeOperation = 'multiply';
- ctx.shadowOffsetX = -10;
- ctx.shadowOffsetY = 10;
- ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
- ctx.shadowBlur = 3;
-
- 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: 'componentTransfer',
- funcA: {type: "table", tableValues: [0, 0.7]}},
- {name: 'dropShadow', dx: 5, dy: 5, floodColor: '#81e'}]});
-
- 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.endLayer();
-
- const outputCanvas = document.getElementById("canvas");
- outputCanvas.getContext('2d').drawImage(canvas, 0, 0);
-</script>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.blending.shadow.no-transform-expected.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.blending.shadow.no-transform-expected.html
new file mode 100644
index 0000000000..d530ef9d19
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.blending.shadow.no-transform-expected.html
@@ -0,0 +1,104 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<title>Canvas test: 2d.layer.global-states.filter.blending.shadow.no-transform</title>
+<h1 style="font-size: 20px;">2d.layer.global-states.filter.blending.shadow.no-transform</h1>
+<p class="desc">Checks that layers with filters correctly use global render states.</p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(2, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>no-globalAlpha</div>
+ <canvas id="canvas0" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas0");
+ const ctx = canvas.getContext('2d');
+
+ const svg = `
+ <svg xmlns="http://www.w3.org/2000/svg"
+ width="90" height="90"
+ color-interpolation-filters="sRGB">
+ <filter id="filter" x="-100%" y="-100%" width="300%" height="300%">
+ <feDropShadow dx="5" dy="5" stdDeviation="0" flood-color="#00f" />
+ <feComponentTransfer>
+ <feFuncA type="table" tableValues="0 0.8"></feFuncA>
+ </feComponentTransfer>
+ </filter>
+ <g filter="url(#filter)">
+ <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>`;
+
+ const img = new Image();
+ img.width = 90;
+ img.height = 90;
+ img.onload = () => {
+ // No transform.
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ // No globalAlpha.
+ ctx.globalCompositeOperation = 'multiply';
+ ctx.shadowOffsetX = -7;
+ ctx.shadowOffsetY = 7;
+ ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
+ ctx.shadowBlur = 3;
+
+ ctx.drawImage(img, 0, 0);
+ };
+ img.src = 'data:image/svg+xml;base64,' + btoa(svg);
+ </script>
+</span>
+
+<span>
+ <div>globalAlpha</div>
+ <canvas id="canvas1" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas1");
+ const ctx = canvas.getContext('2d');
+
+ const svg = `
+ <svg xmlns="http://www.w3.org/2000/svg"
+ width="90" height="90"
+ color-interpolation-filters="sRGB">
+ <filter id="filter" x="-100%" y="-100%" width="300%" height="300%">
+ <feDropShadow dx="5" dy="5" stdDeviation="0" flood-color="#00f" />
+ <feComponentTransfer>
+ <feFuncA type="table" tableValues="0 0.8"></feFuncA>
+ </feComponentTransfer>
+ </filter>
+ <g filter="url(#filter)">
+ <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>`;
+
+ const img = new Image();
+ img.width = 90;
+ img.height = 90;
+ img.onload = () => {
+ // No transform.
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ ctx.globalAlpha = 0.75;
+ ctx.globalCompositeOperation = 'multiply';
+ ctx.shadowOffsetX = -7;
+ ctx.shadowOffsetY = 7;
+ ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
+ ctx.shadowBlur = 3;
+
+ ctx.drawImage(img, 0, 0);
+ };
+ img.src = 'data:image/svg+xml;base64,' + btoa(svg);
+ </script>
+</span>
+
+</div>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.blending.shadow.no-transform.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.blending.shadow.no-transform.html
new file mode 100644
index 0000000000..1ee3254324
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.blending.shadow.no-transform.html
@@ -0,0 +1,91 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<link rel="match" href="2d.layer.global-states.filter.blending.shadow.no-transform-expected.html">
+<title>Canvas test: 2d.layer.global-states.filter.blending.shadow.no-transform</title>
+<h1 style="font-size: 20px;">2d.layer.global-states.filter.blending.shadow.no-transform</h1>
+<p class="desc">Checks that layers with filters correctly use global render states.</p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(2, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>no-globalAlpha</div>
+ <canvas id="canvas0" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(90, 90);
+ const ctx = canvas.getContext('2d');
+
+ // No transform.
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ // No globalAlpha.
+ ctx.globalCompositeOperation = 'multiply';
+ ctx.shadowOffsetX = -7;
+ ctx.shadowOffsetY = 7;
+ ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
+ ctx.shadowBlur = 3;
+
+ ctx.beginLayer({filter: [
+ {name: 'dropShadow',
+ dx: 5, dy: 5, stdDeviation: 0, floodColor: '#00f'},
+ {name: 'componentTransfer',
+ funcA: {type: "table", tableValues: [0, 0.8]}}]});
+
+ 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();
+
+ const outputCanvas = document.getElementById("canvas0");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>globalAlpha</div>
+ <canvas id="canvas1" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(90, 90);
+ const ctx = canvas.getContext('2d');
+
+ // No transform.
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ ctx.globalAlpha = 0.75;
+ ctx.globalCompositeOperation = 'multiply';
+ ctx.shadowOffsetX = -7;
+ ctx.shadowOffsetY = 7;
+ ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
+ ctx.shadowBlur = 3;
+
+ ctx.beginLayer({filter: [
+ {name: 'dropShadow',
+ dx: 5, dy: 5, stdDeviation: 0, floodColor: '#00f'},
+ {name: 'componentTransfer',
+ funcA: {type: "table", tableValues: [0, 0.8]}}]});
+
+ 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();
+
+ const outputCanvas = document.getElementById("canvas1");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+</div>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.blending.shadow.no-transform.w.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.blending.shadow.no-transform.w.html
new file mode 100644
index 0000000000..3ec656c135
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.blending.shadow.no-transform.w.html
@@ -0,0 +1,122 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<html class="reftest-wait">
+<link rel="match" href="2d.layer.global-states.filter.blending.shadow.no-transform-expected.html">
+<title>Canvas test: 2d.layer.global-states.filter.blending.shadow.no-transform</title>
+<h1 style="font-size: 20px;">2d.layer.global-states.filter.blending.shadow.no-transform</h1>
+<p class="desc">Checks that layers with filters correctly use global render states.</p>
+<script>pending_tests = 2;</script>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(2, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>no-globalAlpha</div>
+ <canvas id="canvas0" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script id="myWorker0" type="text/worker">
+ self.onmessage = function(e) {
+ const canvas = new OffscreenCanvas(90, 90);
+ const ctx = canvas.getContext('2d');
+
+ // No transform.
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ // No globalAlpha.
+ ctx.globalCompositeOperation = 'multiply';
+ ctx.shadowOffsetX = -7;
+ ctx.shadowOffsetY = 7;
+ ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
+ ctx.shadowBlur = 3;
+
+ ctx.beginLayer({filter: [
+ {name: 'dropShadow',
+ dx: 5, dy: 5, stdDeviation: 0, floodColor: '#00f'},
+ {name: 'componentTransfer',
+ funcA: {type: "table", tableValues: [0, 0.8]}}]});
+
+ 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();
+
+ const bitmap = canvas.transferToImageBitmap();
+ self.postMessage(bitmap, bitmap);
+ };
+ </script>
+ <script type="module">
+ const blob = new Blob([document.getElementById('myWorker0').textContent]);
+ const worker = new Worker(URL.createObjectURL(blob));
+ worker.addEventListener('message', msg => {
+ const outputCanvas = document.getElementById('canvas0');
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(msg.data, 0, 0);
+ if (--pending_tests == 0) {
+ document.documentElement.classList.remove('reftest-wait');
+ }
+ });
+ worker.postMessage(null);
+ </script>
+</span>
+
+<span>
+ <div>globalAlpha</div>
+ <canvas id="canvas1" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script id="myWorker1" type="text/worker">
+ self.onmessage = function(e) {
+ const canvas = new OffscreenCanvas(90, 90);
+ const ctx = canvas.getContext('2d');
+
+ // No transform.
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ ctx.globalAlpha = 0.75;
+ ctx.globalCompositeOperation = 'multiply';
+ ctx.shadowOffsetX = -7;
+ ctx.shadowOffsetY = 7;
+ ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
+ ctx.shadowBlur = 3;
+
+ ctx.beginLayer({filter: [
+ {name: 'dropShadow',
+ dx: 5, dy: 5, stdDeviation: 0, floodColor: '#00f'},
+ {name: 'componentTransfer',
+ funcA: {type: "table", tableValues: [0, 0.8]}}]});
+
+ 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();
+
+ const bitmap = canvas.transferToImageBitmap();
+ self.postMessage(bitmap, bitmap);
+ };
+ </script>
+ <script type="module">
+ const blob = new Blob([document.getElementById('myWorker1').textContent]);
+ const worker = new Worker(URL.createObjectURL(blob));
+ worker.addEventListener('message', msg => {
+ const outputCanvas = document.getElementById('canvas1');
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(msg.data, 0, 0);
+ if (--pending_tests == 0) {
+ document.documentElement.classList.remove('reftest-wait');
+ }
+ });
+ worker.postMessage(null);
+ </script>
+</span>
+
+</div>
+</html>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.blending.shadow.rotation-expected.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.blending.shadow.rotation-expected.html
new file mode 100644
index 0000000000..80705c36fd
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.blending.shadow.rotation-expected.html
@@ -0,0 +1,108 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<title>Canvas test: 2d.layer.global-states.filter.blending.shadow.rotation</title>
+<h1 style="font-size: 20px;">2d.layer.global-states.filter.blending.shadow.rotation</h1>
+<p class="desc">Checks that layers with filters correctly use global render states.</p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(2, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>no-globalAlpha</div>
+ <canvas id="canvas0" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas0");
+ const ctx = canvas.getContext('2d');
+
+ const svg = `
+ <svg xmlns="http://www.w3.org/2000/svg"
+ width="90" height="90"
+ color-interpolation-filters="sRGB">
+ <filter id="filter" x="-100%" y="-100%" width="300%" height="300%">
+ <feDropShadow dx="5" dy="5" stdDeviation="0" flood-color="#00f" />
+ <feComponentTransfer>
+ <feFuncA type="table" tableValues="0 0.8"></feFuncA>
+ </feComponentTransfer>
+ </filter>
+ <g filter="url(#filter)">
+ <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>`;
+
+ const img = new Image();
+ img.width = 90;
+ img.height = 90;
+ img.onload = () => {
+ ctx.translate(50, 40);
+ ctx.rotate(Math.PI);
+ ctx.translate(-45, -45);
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ // No globalAlpha.
+ ctx.globalCompositeOperation = 'multiply';
+ ctx.shadowOffsetX = -7;
+ ctx.shadowOffsetY = 7;
+ ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
+ ctx.shadowBlur = 3;
+
+ ctx.drawImage(img, 0, 0);
+ };
+ img.src = 'data:image/svg+xml;base64,' + btoa(svg);
+ </script>
+</span>
+
+<span>
+ <div>globalAlpha</div>
+ <canvas id="canvas1" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas1");
+ const ctx = canvas.getContext('2d');
+
+ const svg = `
+ <svg xmlns="http://www.w3.org/2000/svg"
+ width="90" height="90"
+ color-interpolation-filters="sRGB">
+ <filter id="filter" x="-100%" y="-100%" width="300%" height="300%">
+ <feDropShadow dx="5" dy="5" stdDeviation="0" flood-color="#00f" />
+ <feComponentTransfer>
+ <feFuncA type="table" tableValues="0 0.8"></feFuncA>
+ </feComponentTransfer>
+ </filter>
+ <g filter="url(#filter)">
+ <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>`;
+
+ const img = new Image();
+ img.width = 90;
+ img.height = 90;
+ img.onload = () => {
+ ctx.translate(50, 40);
+ ctx.rotate(Math.PI);
+ ctx.translate(-45, -45);
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ ctx.globalAlpha = 0.75;
+ ctx.globalCompositeOperation = 'multiply';
+ ctx.shadowOffsetX = -7;
+ ctx.shadowOffsetY = 7;
+ ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
+ ctx.shadowBlur = 3;
+
+ ctx.drawImage(img, 0, 0);
+ };
+ img.src = 'data:image/svg+xml;base64,' + btoa(svg);
+ </script>
+</span>
+
+</div>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.blending.shadow.rotation.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.blending.shadow.rotation.html
new file mode 100644
index 0000000000..62af08d2ac
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.blending.shadow.rotation.html
@@ -0,0 +1,95 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<link rel="match" href="2d.layer.global-states.filter.blending.shadow.rotation-expected.html">
+<title>Canvas test: 2d.layer.global-states.filter.blending.shadow.rotation</title>
+<h1 style="font-size: 20px;">2d.layer.global-states.filter.blending.shadow.rotation</h1>
+<p class="desc">Checks that layers with filters correctly use global render states.</p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(2, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>no-globalAlpha</div>
+ <canvas id="canvas0" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(90, 90);
+ const ctx = canvas.getContext('2d');
+
+ ctx.translate(50, 40);
+ ctx.rotate(Math.PI);
+ ctx.translate(-45, -45);
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ // No globalAlpha.
+ ctx.globalCompositeOperation = 'multiply';
+ ctx.shadowOffsetX = -7;
+ ctx.shadowOffsetY = 7;
+ ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
+ ctx.shadowBlur = 3;
+
+ ctx.beginLayer({filter: [
+ {name: 'dropShadow',
+ dx: 5, dy: 5, stdDeviation: 0, floodColor: '#00f'},
+ {name: 'componentTransfer',
+ funcA: {type: "table", tableValues: [0, 0.8]}}]});
+
+ 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();
+
+ const outputCanvas = document.getElementById("canvas0");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>globalAlpha</div>
+ <canvas id="canvas1" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(90, 90);
+ const ctx = canvas.getContext('2d');
+
+ ctx.translate(50, 40);
+ ctx.rotate(Math.PI);
+ ctx.translate(-45, -45);
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ ctx.globalAlpha = 0.75;
+ ctx.globalCompositeOperation = 'multiply';
+ ctx.shadowOffsetX = -7;
+ ctx.shadowOffsetY = 7;
+ ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
+ ctx.shadowBlur = 3;
+
+ ctx.beginLayer({filter: [
+ {name: 'dropShadow',
+ dx: 5, dy: 5, stdDeviation: 0, floodColor: '#00f'},
+ {name: 'componentTransfer',
+ funcA: {type: "table", tableValues: [0, 0.8]}}]});
+
+ 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();
+
+ const outputCanvas = document.getElementById("canvas1");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+</div>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.blending.shadow.rotation.w.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.blending.shadow.rotation.w.html
new file mode 100644
index 0000000000..d5693cdcdc
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.blending.shadow.rotation.w.html
@@ -0,0 +1,126 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<html class="reftest-wait">
+<link rel="match" href="2d.layer.global-states.filter.blending.shadow.rotation-expected.html">
+<title>Canvas test: 2d.layer.global-states.filter.blending.shadow.rotation</title>
+<h1 style="font-size: 20px;">2d.layer.global-states.filter.blending.shadow.rotation</h1>
+<p class="desc">Checks that layers with filters correctly use global render states.</p>
+<script>pending_tests = 2;</script>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(2, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>no-globalAlpha</div>
+ <canvas id="canvas0" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script id="myWorker0" type="text/worker">
+ self.onmessage = function(e) {
+ const canvas = new OffscreenCanvas(90, 90);
+ const ctx = canvas.getContext('2d');
+
+ ctx.translate(50, 40);
+ ctx.rotate(Math.PI);
+ ctx.translate(-45, -45);
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ // No globalAlpha.
+ ctx.globalCompositeOperation = 'multiply';
+ ctx.shadowOffsetX = -7;
+ ctx.shadowOffsetY = 7;
+ ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
+ ctx.shadowBlur = 3;
+
+ ctx.beginLayer({filter: [
+ {name: 'dropShadow',
+ dx: 5, dy: 5, stdDeviation: 0, floodColor: '#00f'},
+ {name: 'componentTransfer',
+ funcA: {type: "table", tableValues: [0, 0.8]}}]});
+
+ 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();
+
+ const bitmap = canvas.transferToImageBitmap();
+ self.postMessage(bitmap, bitmap);
+ };
+ </script>
+ <script type="module">
+ const blob = new Blob([document.getElementById('myWorker0').textContent]);
+ const worker = new Worker(URL.createObjectURL(blob));
+ worker.addEventListener('message', msg => {
+ const outputCanvas = document.getElementById('canvas0');
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(msg.data, 0, 0);
+ if (--pending_tests == 0) {
+ document.documentElement.classList.remove('reftest-wait');
+ }
+ });
+ worker.postMessage(null);
+ </script>
+</span>
+
+<span>
+ <div>globalAlpha</div>
+ <canvas id="canvas1" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script id="myWorker1" type="text/worker">
+ self.onmessage = function(e) {
+ const canvas = new OffscreenCanvas(90, 90);
+ const ctx = canvas.getContext('2d');
+
+ ctx.translate(50, 40);
+ ctx.rotate(Math.PI);
+ ctx.translate(-45, -45);
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ ctx.globalAlpha = 0.75;
+ ctx.globalCompositeOperation = 'multiply';
+ ctx.shadowOffsetX = -7;
+ ctx.shadowOffsetY = 7;
+ ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
+ ctx.shadowBlur = 3;
+
+ ctx.beginLayer({filter: [
+ {name: 'dropShadow',
+ dx: 5, dy: 5, stdDeviation: 0, floodColor: '#00f'},
+ {name: 'componentTransfer',
+ funcA: {type: "table", tableValues: [0, 0.8]}}]});
+
+ 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();
+
+ const bitmap = canvas.transferToImageBitmap();
+ self.postMessage(bitmap, bitmap);
+ };
+ </script>
+ <script type="module">
+ const blob = new Blob([document.getElementById('myWorker1').textContent]);
+ const worker = new Worker(URL.createObjectURL(blob));
+ worker.addEventListener('message', msg => {
+ const outputCanvas = document.getElementById('canvas1');
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(msg.data, 0, 0);
+ if (--pending_tests == 0) {
+ document.documentElement.classList.remove('reftest-wait');
+ }
+ });
+ worker.postMessage(null);
+ </script>
+</span>
+
+</div>
+</html>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.blending.shadow.w.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.blending.shadow.w.html
deleted file mode 100644
index ce432ea74d..0000000000
--- a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.blending.shadow.w.html
+++ /dev/null
@@ -1,58 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<html class="reftest-wait">
-<link rel="match" href="2d.layer.global-states.filter.blending.shadow-expected.html">
-<title>Canvas test: 2d.layer.global-states.filter.blending.shadow</title>
-<h1>2d.layer.global-states.filter.blending.shadow</h1>
-<p class="desc">Checks that layers with filters correctly use global render states.</p>
-<canvas id="canvas" width="200" height="200">
- <p class="fallback">FAIL (fallback content)</p>
-</canvas>
-<script id='myWorker' type='text/worker'>
- self.onmessage = function(e) {
- const canvas = new OffscreenCanvas(200, 200);
- const ctx = canvas.getContext('2d');
-
- ctx.fillStyle = 'rgba(0, 0, 255, 1)';
-
- var circle = new Path2D();
- circle.arc(90, 90, 45, 0, 2 * Math.PI);
- ctx.fill(circle);
-
- ctx.globalCompositeOperation = 'multiply';
- ctx.shadowOffsetX = -10;
- ctx.shadowOffsetY = 10;
- ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
- ctx.shadowBlur = 3;
-
- 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: 'componentTransfer',
- funcA: {type: "table", tableValues: [0, 0.7]}},
- {name: 'dropShadow', dx: 5, dy: 5, floodColor: '#81e'}]});
-
- 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.endLayer();
-
- const bitmap = canvas.transferToImageBitmap();
- self.postMessage(bitmap, bitmap);
- };
-</script>
-<script>
- const blob = new Blob([document.getElementById('myWorker').textContent]);
- const worker = new Worker(URL.createObjectURL(blob));
- worker.addEventListener('message', msg => {
- const outputCtx = document.getElementById("canvas").getContext('2d');
- outputCtx.drawImage(msg.data, 0, 0);
- document.documentElement.classList.remove("reftest-wait");
- });
- worker.postMessage(null);
-</script>
-</html>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.blending.w.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.blending.w.html
deleted file mode 100644
index bb101cdc0b..0000000000
--- a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.blending.w.html
+++ /dev/null
@@ -1,54 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<html class="reftest-wait">
-<link rel="match" href="2d.layer.global-states.filter.blending-expected.html">
-<title>Canvas test: 2d.layer.global-states.filter.blending</title>
-<h1>2d.layer.global-states.filter.blending</h1>
-<p class="desc">Checks that layers with filters correctly use global render states.</p>
-<canvas id="canvas" width="200" height="200">
- <p class="fallback">FAIL (fallback content)</p>
-</canvas>
-<script id='myWorker' type='text/worker'>
- self.onmessage = function(e) {
- const canvas = new OffscreenCanvas(200, 200);
- const ctx = canvas.getContext('2d');
-
- ctx.fillStyle = 'rgba(0, 0, 255, 1)';
-
- var circle = new Path2D();
- circle.arc(90, 90, 45, 0, 2 * Math.PI);
- ctx.fill(circle);
-
- ctx.globalCompositeOperation = 'multiply';
-
- 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: 'componentTransfer',
- funcA: {type: "table", tableValues: [0, 0.7]}},
- {name: 'dropShadow', dx: 5, dy: 5, floodColor: '#81e'}]});
-
- 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.endLayer();
-
- const bitmap = canvas.transferToImageBitmap();
- self.postMessage(bitmap, bitmap);
- };
-</script>
-<script>
- const blob = new Blob([document.getElementById('myWorker').textContent]);
- const worker = new Worker(URL.createObjectURL(blob));
- worker.addEventListener('message', msg => {
- const outputCtx = document.getElementById("canvas").getContext('2d');
- outputCtx.drawImage(msg.data, 0, 0);
- document.documentElement.classList.remove("reftest-wait");
- });
- worker.postMessage(null);
-</script>
-</html>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.composite-expected.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.composite-expected.html
deleted file mode 100644
index 97e85a1593..0000000000
--- a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.composite-expected.html
+++ /dev/null
@@ -1,50 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<title>Canvas test: 2d.layer.global-states.filter.composite</title>
-<h1>2d.layer.global-states.filter.composite</h1>
-<p class="desc">Checks that layers with filters correctly use global render states.</p>
-<canvas id="canvas" width="200" height="200">
- <p class="fallback">FAIL (fallback content)</p>
-</canvas>
-<script>
- const canvas = document.getElementById("canvas");
- const ctx = canvas.getContext('2d');
-
- const svg = `
- <svg xmlns="http://www.w3.org/2000/svg"
- width="200" height="200"
- 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" />
- <feComponentTransfer>
- <feFuncA type="table" tableValues="0 0.7"></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)"/>
- </g>
- </svg>`;
-
- const img = new Image();
- img.width = 200;
- img.height = 200;
- img.onload = () => {
- ctx.fillStyle = 'rgba(0, 0, 255, 1)';
-
- var circle = new Path2D();
- circle.arc(90, 90, 45, 0, 2 * Math.PI);
- ctx.fill(circle);
-
- ctx.globalCompositeOperation = 'source-in';
-
- ctx.drawImage(img, 0, 0);
- };
- img.src = 'data:image/svg+xml;base64,' + btoa(svg);
-</script>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.composite.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.composite.html
deleted file mode 100644
index 32052a1150..0000000000
--- a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.composite.html
+++ /dev/null
@@ -1,40 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<link rel="match" href="2d.layer.global-states.filter.composite-expected.html">
-<title>Canvas test: 2d.layer.global-states.filter.composite</title>
-<h1>2d.layer.global-states.filter.composite</h1>
-<p class="desc">Checks that layers with filters correctly use global render states.</p>
-<canvas id="canvas" width="200" height="200">
- <p class="fallback">FAIL (fallback content)</p>
-</canvas>
-<script>
- const canvas = new OffscreenCanvas(200, 200);
- const ctx = canvas.getContext('2d');
-
- ctx.fillStyle = 'rgba(0, 0, 255, 1)';
-
- var circle = new Path2D();
- circle.arc(90, 90, 45, 0, 2 * Math.PI);
- ctx.fill(circle);
-
- ctx.globalCompositeOperation = 'source-in';
-
- 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: 'componentTransfer',
- funcA: {type: "table", tableValues: [0, 0.7]}},
- {name: 'dropShadow', dx: 5, dy: 5, floodColor: '#81e'}]});
-
- 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.endLayer();
-
- const outputCanvas = document.getElementById("canvas");
- outputCanvas.getContext('2d').drawImage(canvas, 0, 0);
-</script>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.composite.no-shadow.no-transform-expected.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.composite.no-shadow.no-transform-expected.html
new file mode 100644
index 0000000000..2f513bff0a
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.composite.no-shadow.no-transform-expected.html
@@ -0,0 +1,98 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<title>Canvas test: 2d.layer.global-states.filter.composite.no-shadow.no-transform</title>
+<h1 style="font-size: 20px;">2d.layer.global-states.filter.composite.no-shadow.no-transform</h1>
+<p class="desc">Checks that layers with filters correctly use global render states.</p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(2, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>no-globalAlpha</div>
+ <canvas id="canvas0" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas0");
+ const ctx = canvas.getContext('2d');
+
+ const svg = `
+ <svg xmlns="http://www.w3.org/2000/svg"
+ width="90" height="90"
+ color-interpolation-filters="sRGB">
+ <filter id="filter" x="-100%" y="-100%" width="300%" height="300%">
+ <feDropShadow dx="5" dy="5" stdDeviation="0" flood-color="#00f" />
+ <feComponentTransfer>
+ <feFuncA type="table" tableValues="0 0.8"></feFuncA>
+ </feComponentTransfer>
+ </filter>
+ <g filter="url(#filter)">
+ <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>`;
+
+ const img = new Image();
+ img.width = 90;
+ img.height = 90;
+ img.onload = () => {
+ // No transform.
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ // No globalAlpha.
+ ctx.globalCompositeOperation = 'source-in';
+ // No shadow.
+
+ ctx.drawImage(img, 0, 0);
+ };
+ img.src = 'data:image/svg+xml;base64,' + btoa(svg);
+ </script>
+</span>
+
+<span>
+ <div>globalAlpha</div>
+ <canvas id="canvas1" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas1");
+ const ctx = canvas.getContext('2d');
+
+ const svg = `
+ <svg xmlns="http://www.w3.org/2000/svg"
+ width="90" height="90"
+ color-interpolation-filters="sRGB">
+ <filter id="filter" x="-100%" y="-100%" width="300%" height="300%">
+ <feDropShadow dx="5" dy="5" stdDeviation="0" flood-color="#00f" />
+ <feComponentTransfer>
+ <feFuncA type="table" tableValues="0 0.8"></feFuncA>
+ </feComponentTransfer>
+ </filter>
+ <g filter="url(#filter)">
+ <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>`;
+
+ const img = new Image();
+ img.width = 90;
+ img.height = 90;
+ img.onload = () => {
+ // No transform.
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ ctx.globalAlpha = 0.75;
+ ctx.globalCompositeOperation = 'source-in';
+ // No shadow.
+
+ ctx.drawImage(img, 0, 0);
+ };
+ img.src = 'data:image/svg+xml;base64,' + btoa(svg);
+ </script>
+</span>
+
+</div>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.composite.no-shadow.no-transform.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.composite.no-shadow.no-transform.html
new file mode 100644
index 0000000000..17394aa4c8
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.composite.no-shadow.no-transform.html
@@ -0,0 +1,85 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<link rel="match" href="2d.layer.global-states.filter.composite.no-shadow.no-transform-expected.html">
+<title>Canvas test: 2d.layer.global-states.filter.composite.no-shadow.no-transform</title>
+<h1 style="font-size: 20px;">2d.layer.global-states.filter.composite.no-shadow.no-transform</h1>
+<p class="desc">Checks that layers with filters correctly use global render states.</p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(2, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>no-globalAlpha</div>
+ <canvas id="canvas0" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(90, 90);
+ const ctx = canvas.getContext('2d');
+
+ // No transform.
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ // No globalAlpha.
+ ctx.globalCompositeOperation = 'source-in';
+ // No shadow.
+
+ ctx.beginLayer({filter: [
+ {name: 'dropShadow',
+ dx: 5, dy: 5, stdDeviation: 0, floodColor: '#00f'},
+ {name: 'componentTransfer',
+ funcA: {type: "table", tableValues: [0, 0.8]}}]});
+
+ 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();
+
+ const outputCanvas = document.getElementById("canvas0");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>globalAlpha</div>
+ <canvas id="canvas1" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(90, 90);
+ const ctx = canvas.getContext('2d');
+
+ // No transform.
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ ctx.globalAlpha = 0.75;
+ ctx.globalCompositeOperation = 'source-in';
+ // No shadow.
+
+ ctx.beginLayer({filter: [
+ {name: 'dropShadow',
+ dx: 5, dy: 5, stdDeviation: 0, floodColor: '#00f'},
+ {name: 'componentTransfer',
+ funcA: {type: "table", tableValues: [0, 0.8]}}]});
+
+ 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();
+
+ const outputCanvas = document.getElementById("canvas1");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+</div>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.composite.no-shadow.no-transform.w.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.composite.no-shadow.no-transform.w.html
new file mode 100644
index 0000000000..386ad43b0f
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.composite.no-shadow.no-transform.w.html
@@ -0,0 +1,116 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<html class="reftest-wait">
+<link rel="match" href="2d.layer.global-states.filter.composite.no-shadow.no-transform-expected.html">
+<title>Canvas test: 2d.layer.global-states.filter.composite.no-shadow.no-transform</title>
+<h1 style="font-size: 20px;">2d.layer.global-states.filter.composite.no-shadow.no-transform</h1>
+<p class="desc">Checks that layers with filters correctly use global render states.</p>
+<script>pending_tests = 2;</script>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(2, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>no-globalAlpha</div>
+ <canvas id="canvas0" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script id="myWorker0" type="text/worker">
+ self.onmessage = function(e) {
+ const canvas = new OffscreenCanvas(90, 90);
+ const ctx = canvas.getContext('2d');
+
+ // No transform.
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ // No globalAlpha.
+ ctx.globalCompositeOperation = 'source-in';
+ // No shadow.
+
+ ctx.beginLayer({filter: [
+ {name: 'dropShadow',
+ dx: 5, dy: 5, stdDeviation: 0, floodColor: '#00f'},
+ {name: 'componentTransfer',
+ funcA: {type: "table", tableValues: [0, 0.8]}}]});
+
+ 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();
+
+ const bitmap = canvas.transferToImageBitmap();
+ self.postMessage(bitmap, bitmap);
+ };
+ </script>
+ <script type="module">
+ const blob = new Blob([document.getElementById('myWorker0').textContent]);
+ const worker = new Worker(URL.createObjectURL(blob));
+ worker.addEventListener('message', msg => {
+ const outputCanvas = document.getElementById('canvas0');
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(msg.data, 0, 0);
+ if (--pending_tests == 0) {
+ document.documentElement.classList.remove('reftest-wait');
+ }
+ });
+ worker.postMessage(null);
+ </script>
+</span>
+
+<span>
+ <div>globalAlpha</div>
+ <canvas id="canvas1" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script id="myWorker1" type="text/worker">
+ self.onmessage = function(e) {
+ const canvas = new OffscreenCanvas(90, 90);
+ const ctx = canvas.getContext('2d');
+
+ // No transform.
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ ctx.globalAlpha = 0.75;
+ ctx.globalCompositeOperation = 'source-in';
+ // No shadow.
+
+ ctx.beginLayer({filter: [
+ {name: 'dropShadow',
+ dx: 5, dy: 5, stdDeviation: 0, floodColor: '#00f'},
+ {name: 'componentTransfer',
+ funcA: {type: "table", tableValues: [0, 0.8]}}]});
+
+ 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();
+
+ const bitmap = canvas.transferToImageBitmap();
+ self.postMessage(bitmap, bitmap);
+ };
+ </script>
+ <script type="module">
+ const blob = new Blob([document.getElementById('myWorker1').textContent]);
+ const worker = new Worker(URL.createObjectURL(blob));
+ worker.addEventListener('message', msg => {
+ const outputCanvas = document.getElementById('canvas1');
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(msg.data, 0, 0);
+ if (--pending_tests == 0) {
+ document.documentElement.classList.remove('reftest-wait');
+ }
+ });
+ worker.postMessage(null);
+ </script>
+</span>
+
+</div>
+</html>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.composite.no-shadow.rotation-expected.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.composite.no-shadow.rotation-expected.html
new file mode 100644
index 0000000000..242973300f
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.composite.no-shadow.rotation-expected.html
@@ -0,0 +1,102 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<title>Canvas test: 2d.layer.global-states.filter.composite.no-shadow.rotation</title>
+<h1 style="font-size: 20px;">2d.layer.global-states.filter.composite.no-shadow.rotation</h1>
+<p class="desc">Checks that layers with filters correctly use global render states.</p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(2, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>no-globalAlpha</div>
+ <canvas id="canvas0" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas0");
+ const ctx = canvas.getContext('2d');
+
+ const svg = `
+ <svg xmlns="http://www.w3.org/2000/svg"
+ width="90" height="90"
+ color-interpolation-filters="sRGB">
+ <filter id="filter" x="-100%" y="-100%" width="300%" height="300%">
+ <feDropShadow dx="5" dy="5" stdDeviation="0" flood-color="#00f" />
+ <feComponentTransfer>
+ <feFuncA type="table" tableValues="0 0.8"></feFuncA>
+ </feComponentTransfer>
+ </filter>
+ <g filter="url(#filter)">
+ <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>`;
+
+ const img = new Image();
+ img.width = 90;
+ img.height = 90;
+ img.onload = () => {
+ ctx.translate(50, 40);
+ ctx.rotate(Math.PI);
+ ctx.translate(-45, -45);
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ // No globalAlpha.
+ ctx.globalCompositeOperation = 'source-in';
+ // No shadow.
+
+ ctx.drawImage(img, 0, 0);
+ };
+ img.src = 'data:image/svg+xml;base64,' + btoa(svg);
+ </script>
+</span>
+
+<span>
+ <div>globalAlpha</div>
+ <canvas id="canvas1" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas1");
+ const ctx = canvas.getContext('2d');
+
+ const svg = `
+ <svg xmlns="http://www.w3.org/2000/svg"
+ width="90" height="90"
+ color-interpolation-filters="sRGB">
+ <filter id="filter" x="-100%" y="-100%" width="300%" height="300%">
+ <feDropShadow dx="5" dy="5" stdDeviation="0" flood-color="#00f" />
+ <feComponentTransfer>
+ <feFuncA type="table" tableValues="0 0.8"></feFuncA>
+ </feComponentTransfer>
+ </filter>
+ <g filter="url(#filter)">
+ <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>`;
+
+ const img = new Image();
+ img.width = 90;
+ img.height = 90;
+ img.onload = () => {
+ ctx.translate(50, 40);
+ ctx.rotate(Math.PI);
+ ctx.translate(-45, -45);
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ ctx.globalAlpha = 0.75;
+ ctx.globalCompositeOperation = 'source-in';
+ // No shadow.
+
+ ctx.drawImage(img, 0, 0);
+ };
+ img.src = 'data:image/svg+xml;base64,' + btoa(svg);
+ </script>
+</span>
+
+</div>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.composite.no-shadow.rotation.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.composite.no-shadow.rotation.html
new file mode 100644
index 0000000000..576283ea73
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.composite.no-shadow.rotation.html
@@ -0,0 +1,89 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<link rel="match" href="2d.layer.global-states.filter.composite.no-shadow.rotation-expected.html">
+<title>Canvas test: 2d.layer.global-states.filter.composite.no-shadow.rotation</title>
+<h1 style="font-size: 20px;">2d.layer.global-states.filter.composite.no-shadow.rotation</h1>
+<p class="desc">Checks that layers with filters correctly use global render states.</p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(2, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>no-globalAlpha</div>
+ <canvas id="canvas0" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(90, 90);
+ const ctx = canvas.getContext('2d');
+
+ ctx.translate(50, 40);
+ ctx.rotate(Math.PI);
+ ctx.translate(-45, -45);
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ // No globalAlpha.
+ ctx.globalCompositeOperation = 'source-in';
+ // No shadow.
+
+ ctx.beginLayer({filter: [
+ {name: 'dropShadow',
+ dx: 5, dy: 5, stdDeviation: 0, floodColor: '#00f'},
+ {name: 'componentTransfer',
+ funcA: {type: "table", tableValues: [0, 0.8]}}]});
+
+ 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();
+
+ const outputCanvas = document.getElementById("canvas0");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>globalAlpha</div>
+ <canvas id="canvas1" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(90, 90);
+ const ctx = canvas.getContext('2d');
+
+ ctx.translate(50, 40);
+ ctx.rotate(Math.PI);
+ ctx.translate(-45, -45);
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ ctx.globalAlpha = 0.75;
+ ctx.globalCompositeOperation = 'source-in';
+ // No shadow.
+
+ ctx.beginLayer({filter: [
+ {name: 'dropShadow',
+ dx: 5, dy: 5, stdDeviation: 0, floodColor: '#00f'},
+ {name: 'componentTransfer',
+ funcA: {type: "table", tableValues: [0, 0.8]}}]});
+
+ 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();
+
+ const outputCanvas = document.getElementById("canvas1");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+</div>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.composite.no-shadow.rotation.w.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.composite.no-shadow.rotation.w.html
new file mode 100644
index 0000000000..6dd39d77e9
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.composite.no-shadow.rotation.w.html
@@ -0,0 +1,120 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<html class="reftest-wait">
+<link rel="match" href="2d.layer.global-states.filter.composite.no-shadow.rotation-expected.html">
+<title>Canvas test: 2d.layer.global-states.filter.composite.no-shadow.rotation</title>
+<h1 style="font-size: 20px;">2d.layer.global-states.filter.composite.no-shadow.rotation</h1>
+<p class="desc">Checks that layers with filters correctly use global render states.</p>
+<script>pending_tests = 2;</script>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(2, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>no-globalAlpha</div>
+ <canvas id="canvas0" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script id="myWorker0" type="text/worker">
+ self.onmessage = function(e) {
+ const canvas = new OffscreenCanvas(90, 90);
+ const ctx = canvas.getContext('2d');
+
+ ctx.translate(50, 40);
+ ctx.rotate(Math.PI);
+ ctx.translate(-45, -45);
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ // No globalAlpha.
+ ctx.globalCompositeOperation = 'source-in';
+ // No shadow.
+
+ ctx.beginLayer({filter: [
+ {name: 'dropShadow',
+ dx: 5, dy: 5, stdDeviation: 0, floodColor: '#00f'},
+ {name: 'componentTransfer',
+ funcA: {type: "table", tableValues: [0, 0.8]}}]});
+
+ 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();
+
+ const bitmap = canvas.transferToImageBitmap();
+ self.postMessage(bitmap, bitmap);
+ };
+ </script>
+ <script type="module">
+ const blob = new Blob([document.getElementById('myWorker0').textContent]);
+ const worker = new Worker(URL.createObjectURL(blob));
+ worker.addEventListener('message', msg => {
+ const outputCanvas = document.getElementById('canvas0');
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(msg.data, 0, 0);
+ if (--pending_tests == 0) {
+ document.documentElement.classList.remove('reftest-wait');
+ }
+ });
+ worker.postMessage(null);
+ </script>
+</span>
+
+<span>
+ <div>globalAlpha</div>
+ <canvas id="canvas1" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script id="myWorker1" type="text/worker">
+ self.onmessage = function(e) {
+ const canvas = new OffscreenCanvas(90, 90);
+ const ctx = canvas.getContext('2d');
+
+ ctx.translate(50, 40);
+ ctx.rotate(Math.PI);
+ ctx.translate(-45, -45);
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ ctx.globalAlpha = 0.75;
+ ctx.globalCompositeOperation = 'source-in';
+ // No shadow.
+
+ ctx.beginLayer({filter: [
+ {name: 'dropShadow',
+ dx: 5, dy: 5, stdDeviation: 0, floodColor: '#00f'},
+ {name: 'componentTransfer',
+ funcA: {type: "table", tableValues: [0, 0.8]}}]});
+
+ 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();
+
+ const bitmap = canvas.transferToImageBitmap();
+ self.postMessage(bitmap, bitmap);
+ };
+ </script>
+ <script type="module">
+ const blob = new Blob([document.getElementById('myWorker1').textContent]);
+ const worker = new Worker(URL.createObjectURL(blob));
+ worker.addEventListener('message', msg => {
+ const outputCanvas = document.getElementById('canvas1');
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(msg.data, 0, 0);
+ if (--pending_tests == 0) {
+ document.documentElement.classList.remove('reftest-wait');
+ }
+ });
+ worker.postMessage(null);
+ </script>
+</span>
+
+</div>
+</html>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.composite.shadow-expected.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.composite.shadow-expected.html
deleted file mode 100644
index 4716bb2760..0000000000
--- a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.composite.shadow-expected.html
+++ /dev/null
@@ -1,54 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<title>Canvas test: 2d.layer.global-states.filter.composite.shadow</title>
-<h1>2d.layer.global-states.filter.composite.shadow</h1>
-<p class="desc">Checks that layers with filters correctly use global render states.</p>
-<canvas id="canvas" width="200" height="200">
- <p class="fallback">FAIL (fallback content)</p>
-</canvas>
-<script>
- const canvas = document.getElementById("canvas");
- const ctx = canvas.getContext('2d');
-
- const svg = `
- <svg xmlns="http://www.w3.org/2000/svg"
- width="200" height="200"
- 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" />
- <feComponentTransfer>
- <feFuncA type="table" tableValues="0 0.7"></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)"/>
- </g>
- </svg>`;
-
- const img = new Image();
- img.width = 200;
- img.height = 200;
- img.onload = () => {
- ctx.fillStyle = 'rgba(0, 0, 255, 1)';
-
- var circle = new Path2D();
- circle.arc(90, 90, 45, 0, 2 * Math.PI);
- ctx.fill(circle);
-
- ctx.globalCompositeOperation = 'source-in';
- ctx.shadowOffsetX = -10;
- ctx.shadowOffsetY = 10;
- ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
- ctx.shadowBlur = 3;
-
- ctx.drawImage(img, 0, 0);
- };
- img.src = 'data:image/svg+xml;base64,' + btoa(svg);
-</script>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.composite.shadow.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.composite.shadow.html
deleted file mode 100644
index b5e8b9f843..0000000000
--- a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.composite.shadow.html
+++ /dev/null
@@ -1,44 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<link rel="match" href="2d.layer.global-states.filter.composite.shadow-expected.html">
-<title>Canvas test: 2d.layer.global-states.filter.composite.shadow</title>
-<h1>2d.layer.global-states.filter.composite.shadow</h1>
-<p class="desc">Checks that layers with filters correctly use global render states.</p>
-<canvas id="canvas" width="200" height="200">
- <p class="fallback">FAIL (fallback content)</p>
-</canvas>
-<script>
- const canvas = new OffscreenCanvas(200, 200);
- const ctx = canvas.getContext('2d');
-
- ctx.fillStyle = 'rgba(0, 0, 255, 1)';
-
- var circle = new Path2D();
- circle.arc(90, 90, 45, 0, 2 * Math.PI);
- ctx.fill(circle);
-
- ctx.globalCompositeOperation = 'source-in';
- ctx.shadowOffsetX = -10;
- ctx.shadowOffsetY = 10;
- ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
- ctx.shadowBlur = 3;
-
- 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: 'componentTransfer',
- funcA: {type: "table", tableValues: [0, 0.7]}},
- {name: 'dropShadow', dx: 5, dy: 5, floodColor: '#81e'}]});
-
- 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.endLayer();
-
- const outputCanvas = document.getElementById("canvas");
- outputCanvas.getContext('2d').drawImage(canvas, 0, 0);
-</script>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.composite.shadow.no-transform-expected.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.composite.shadow.no-transform-expected.html
new file mode 100644
index 0000000000..c8926e5e15
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.composite.shadow.no-transform-expected.html
@@ -0,0 +1,104 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<title>Canvas test: 2d.layer.global-states.filter.composite.shadow.no-transform</title>
+<h1 style="font-size: 20px;">2d.layer.global-states.filter.composite.shadow.no-transform</h1>
+<p class="desc">Checks that layers with filters correctly use global render states.</p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(2, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>no-globalAlpha</div>
+ <canvas id="canvas0" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas0");
+ const ctx = canvas.getContext('2d');
+
+ const svg = `
+ <svg xmlns="http://www.w3.org/2000/svg"
+ width="90" height="90"
+ color-interpolation-filters="sRGB">
+ <filter id="filter" x="-100%" y="-100%" width="300%" height="300%">
+ <feDropShadow dx="5" dy="5" stdDeviation="0" flood-color="#00f" />
+ <feComponentTransfer>
+ <feFuncA type="table" tableValues="0 0.8"></feFuncA>
+ </feComponentTransfer>
+ </filter>
+ <g filter="url(#filter)">
+ <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>`;
+
+ const img = new Image();
+ img.width = 90;
+ img.height = 90;
+ img.onload = () => {
+ // No transform.
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ // No globalAlpha.
+ ctx.globalCompositeOperation = 'source-in';
+ ctx.shadowOffsetX = -7;
+ ctx.shadowOffsetY = 7;
+ ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
+ ctx.shadowBlur = 3;
+
+ ctx.drawImage(img, 0, 0);
+ };
+ img.src = 'data:image/svg+xml;base64,' + btoa(svg);
+ </script>
+</span>
+
+<span>
+ <div>globalAlpha</div>
+ <canvas id="canvas1" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas1");
+ const ctx = canvas.getContext('2d');
+
+ const svg = `
+ <svg xmlns="http://www.w3.org/2000/svg"
+ width="90" height="90"
+ color-interpolation-filters="sRGB">
+ <filter id="filter" x="-100%" y="-100%" width="300%" height="300%">
+ <feDropShadow dx="5" dy="5" stdDeviation="0" flood-color="#00f" />
+ <feComponentTransfer>
+ <feFuncA type="table" tableValues="0 0.8"></feFuncA>
+ </feComponentTransfer>
+ </filter>
+ <g filter="url(#filter)">
+ <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>`;
+
+ const img = new Image();
+ img.width = 90;
+ img.height = 90;
+ img.onload = () => {
+ // No transform.
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ ctx.globalAlpha = 0.75;
+ ctx.globalCompositeOperation = 'source-in';
+ ctx.shadowOffsetX = -7;
+ ctx.shadowOffsetY = 7;
+ ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
+ ctx.shadowBlur = 3;
+
+ ctx.drawImage(img, 0, 0);
+ };
+ img.src = 'data:image/svg+xml;base64,' + btoa(svg);
+ </script>
+</span>
+
+</div>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.composite.shadow.no-transform.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.composite.shadow.no-transform.html
new file mode 100644
index 0000000000..b574a819d6
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.composite.shadow.no-transform.html
@@ -0,0 +1,91 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<link rel="match" href="2d.layer.global-states.filter.composite.shadow.no-transform-expected.html">
+<title>Canvas test: 2d.layer.global-states.filter.composite.shadow.no-transform</title>
+<h1 style="font-size: 20px;">2d.layer.global-states.filter.composite.shadow.no-transform</h1>
+<p class="desc">Checks that layers with filters correctly use global render states.</p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(2, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>no-globalAlpha</div>
+ <canvas id="canvas0" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(90, 90);
+ const ctx = canvas.getContext('2d');
+
+ // No transform.
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ // No globalAlpha.
+ ctx.globalCompositeOperation = 'source-in';
+ ctx.shadowOffsetX = -7;
+ ctx.shadowOffsetY = 7;
+ ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
+ ctx.shadowBlur = 3;
+
+ ctx.beginLayer({filter: [
+ {name: 'dropShadow',
+ dx: 5, dy: 5, stdDeviation: 0, floodColor: '#00f'},
+ {name: 'componentTransfer',
+ funcA: {type: "table", tableValues: [0, 0.8]}}]});
+
+ 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();
+
+ const outputCanvas = document.getElementById("canvas0");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>globalAlpha</div>
+ <canvas id="canvas1" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(90, 90);
+ const ctx = canvas.getContext('2d');
+
+ // No transform.
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ ctx.globalAlpha = 0.75;
+ ctx.globalCompositeOperation = 'source-in';
+ ctx.shadowOffsetX = -7;
+ ctx.shadowOffsetY = 7;
+ ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
+ ctx.shadowBlur = 3;
+
+ ctx.beginLayer({filter: [
+ {name: 'dropShadow',
+ dx: 5, dy: 5, stdDeviation: 0, floodColor: '#00f'},
+ {name: 'componentTransfer',
+ funcA: {type: "table", tableValues: [0, 0.8]}}]});
+
+ 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();
+
+ const outputCanvas = document.getElementById("canvas1");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+</div>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.composite.shadow.no-transform.w.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.composite.shadow.no-transform.w.html
new file mode 100644
index 0000000000..96ee1b027b
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.composite.shadow.no-transform.w.html
@@ -0,0 +1,122 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<html class="reftest-wait">
+<link rel="match" href="2d.layer.global-states.filter.composite.shadow.no-transform-expected.html">
+<title>Canvas test: 2d.layer.global-states.filter.composite.shadow.no-transform</title>
+<h1 style="font-size: 20px;">2d.layer.global-states.filter.composite.shadow.no-transform</h1>
+<p class="desc">Checks that layers with filters correctly use global render states.</p>
+<script>pending_tests = 2;</script>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(2, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>no-globalAlpha</div>
+ <canvas id="canvas0" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script id="myWorker0" type="text/worker">
+ self.onmessage = function(e) {
+ const canvas = new OffscreenCanvas(90, 90);
+ const ctx = canvas.getContext('2d');
+
+ // No transform.
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ // No globalAlpha.
+ ctx.globalCompositeOperation = 'source-in';
+ ctx.shadowOffsetX = -7;
+ ctx.shadowOffsetY = 7;
+ ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
+ ctx.shadowBlur = 3;
+
+ ctx.beginLayer({filter: [
+ {name: 'dropShadow',
+ dx: 5, dy: 5, stdDeviation: 0, floodColor: '#00f'},
+ {name: 'componentTransfer',
+ funcA: {type: "table", tableValues: [0, 0.8]}}]});
+
+ 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();
+
+ const bitmap = canvas.transferToImageBitmap();
+ self.postMessage(bitmap, bitmap);
+ };
+ </script>
+ <script type="module">
+ const blob = new Blob([document.getElementById('myWorker0').textContent]);
+ const worker = new Worker(URL.createObjectURL(blob));
+ worker.addEventListener('message', msg => {
+ const outputCanvas = document.getElementById('canvas0');
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(msg.data, 0, 0);
+ if (--pending_tests == 0) {
+ document.documentElement.classList.remove('reftest-wait');
+ }
+ });
+ worker.postMessage(null);
+ </script>
+</span>
+
+<span>
+ <div>globalAlpha</div>
+ <canvas id="canvas1" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script id="myWorker1" type="text/worker">
+ self.onmessage = function(e) {
+ const canvas = new OffscreenCanvas(90, 90);
+ const ctx = canvas.getContext('2d');
+
+ // No transform.
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ ctx.globalAlpha = 0.75;
+ ctx.globalCompositeOperation = 'source-in';
+ ctx.shadowOffsetX = -7;
+ ctx.shadowOffsetY = 7;
+ ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
+ ctx.shadowBlur = 3;
+
+ ctx.beginLayer({filter: [
+ {name: 'dropShadow',
+ dx: 5, dy: 5, stdDeviation: 0, floodColor: '#00f'},
+ {name: 'componentTransfer',
+ funcA: {type: "table", tableValues: [0, 0.8]}}]});
+
+ 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();
+
+ const bitmap = canvas.transferToImageBitmap();
+ self.postMessage(bitmap, bitmap);
+ };
+ </script>
+ <script type="module">
+ const blob = new Blob([document.getElementById('myWorker1').textContent]);
+ const worker = new Worker(URL.createObjectURL(blob));
+ worker.addEventListener('message', msg => {
+ const outputCanvas = document.getElementById('canvas1');
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(msg.data, 0, 0);
+ if (--pending_tests == 0) {
+ document.documentElement.classList.remove('reftest-wait');
+ }
+ });
+ worker.postMessage(null);
+ </script>
+</span>
+
+</div>
+</html>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.composite.shadow.rotation-expected.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.composite.shadow.rotation-expected.html
new file mode 100644
index 0000000000..e70fe3e92d
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.composite.shadow.rotation-expected.html
@@ -0,0 +1,108 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<title>Canvas test: 2d.layer.global-states.filter.composite.shadow.rotation</title>
+<h1 style="font-size: 20px;">2d.layer.global-states.filter.composite.shadow.rotation</h1>
+<p class="desc">Checks that layers with filters correctly use global render states.</p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(2, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>no-globalAlpha</div>
+ <canvas id="canvas0" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas0");
+ const ctx = canvas.getContext('2d');
+
+ const svg = `
+ <svg xmlns="http://www.w3.org/2000/svg"
+ width="90" height="90"
+ color-interpolation-filters="sRGB">
+ <filter id="filter" x="-100%" y="-100%" width="300%" height="300%">
+ <feDropShadow dx="5" dy="5" stdDeviation="0" flood-color="#00f" />
+ <feComponentTransfer>
+ <feFuncA type="table" tableValues="0 0.8"></feFuncA>
+ </feComponentTransfer>
+ </filter>
+ <g filter="url(#filter)">
+ <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>`;
+
+ const img = new Image();
+ img.width = 90;
+ img.height = 90;
+ img.onload = () => {
+ ctx.translate(50, 40);
+ ctx.rotate(Math.PI);
+ ctx.translate(-45, -45);
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ // No globalAlpha.
+ ctx.globalCompositeOperation = 'source-in';
+ ctx.shadowOffsetX = -7;
+ ctx.shadowOffsetY = 7;
+ ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
+ ctx.shadowBlur = 3;
+
+ ctx.drawImage(img, 0, 0);
+ };
+ img.src = 'data:image/svg+xml;base64,' + btoa(svg);
+ </script>
+</span>
+
+<span>
+ <div>globalAlpha</div>
+ <canvas id="canvas1" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas1");
+ const ctx = canvas.getContext('2d');
+
+ const svg = `
+ <svg xmlns="http://www.w3.org/2000/svg"
+ width="90" height="90"
+ color-interpolation-filters="sRGB">
+ <filter id="filter" x="-100%" y="-100%" width="300%" height="300%">
+ <feDropShadow dx="5" dy="5" stdDeviation="0" flood-color="#00f" />
+ <feComponentTransfer>
+ <feFuncA type="table" tableValues="0 0.8"></feFuncA>
+ </feComponentTransfer>
+ </filter>
+ <g filter="url(#filter)">
+ <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>`;
+
+ const img = new Image();
+ img.width = 90;
+ img.height = 90;
+ img.onload = () => {
+ ctx.translate(50, 40);
+ ctx.rotate(Math.PI);
+ ctx.translate(-45, -45);
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ ctx.globalAlpha = 0.75;
+ ctx.globalCompositeOperation = 'source-in';
+ ctx.shadowOffsetX = -7;
+ ctx.shadowOffsetY = 7;
+ ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
+ ctx.shadowBlur = 3;
+
+ ctx.drawImage(img, 0, 0);
+ };
+ img.src = 'data:image/svg+xml;base64,' + btoa(svg);
+ </script>
+</span>
+
+</div>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.composite.shadow.rotation.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.composite.shadow.rotation.html
new file mode 100644
index 0000000000..b7b4312a35
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.composite.shadow.rotation.html
@@ -0,0 +1,95 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<link rel="match" href="2d.layer.global-states.filter.composite.shadow.rotation-expected.html">
+<title>Canvas test: 2d.layer.global-states.filter.composite.shadow.rotation</title>
+<h1 style="font-size: 20px;">2d.layer.global-states.filter.composite.shadow.rotation</h1>
+<p class="desc">Checks that layers with filters correctly use global render states.</p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(2, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>no-globalAlpha</div>
+ <canvas id="canvas0" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(90, 90);
+ const ctx = canvas.getContext('2d');
+
+ ctx.translate(50, 40);
+ ctx.rotate(Math.PI);
+ ctx.translate(-45, -45);
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ // No globalAlpha.
+ ctx.globalCompositeOperation = 'source-in';
+ ctx.shadowOffsetX = -7;
+ ctx.shadowOffsetY = 7;
+ ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
+ ctx.shadowBlur = 3;
+
+ ctx.beginLayer({filter: [
+ {name: 'dropShadow',
+ dx: 5, dy: 5, stdDeviation: 0, floodColor: '#00f'},
+ {name: 'componentTransfer',
+ funcA: {type: "table", tableValues: [0, 0.8]}}]});
+
+ 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();
+
+ const outputCanvas = document.getElementById("canvas0");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>globalAlpha</div>
+ <canvas id="canvas1" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(90, 90);
+ const ctx = canvas.getContext('2d');
+
+ ctx.translate(50, 40);
+ ctx.rotate(Math.PI);
+ ctx.translate(-45, -45);
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ ctx.globalAlpha = 0.75;
+ ctx.globalCompositeOperation = 'source-in';
+ ctx.shadowOffsetX = -7;
+ ctx.shadowOffsetY = 7;
+ ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
+ ctx.shadowBlur = 3;
+
+ ctx.beginLayer({filter: [
+ {name: 'dropShadow',
+ dx: 5, dy: 5, stdDeviation: 0, floodColor: '#00f'},
+ {name: 'componentTransfer',
+ funcA: {type: "table", tableValues: [0, 0.8]}}]});
+
+ 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();
+
+ const outputCanvas = document.getElementById("canvas1");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+</div>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.composite.shadow.rotation.w.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.composite.shadow.rotation.w.html
new file mode 100644
index 0000000000..1ae9f00a85
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.composite.shadow.rotation.w.html
@@ -0,0 +1,126 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<html class="reftest-wait">
+<link rel="match" href="2d.layer.global-states.filter.composite.shadow.rotation-expected.html">
+<title>Canvas test: 2d.layer.global-states.filter.composite.shadow.rotation</title>
+<h1 style="font-size: 20px;">2d.layer.global-states.filter.composite.shadow.rotation</h1>
+<p class="desc">Checks that layers with filters correctly use global render states.</p>
+<script>pending_tests = 2;</script>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(2, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>no-globalAlpha</div>
+ <canvas id="canvas0" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script id="myWorker0" type="text/worker">
+ self.onmessage = function(e) {
+ const canvas = new OffscreenCanvas(90, 90);
+ const ctx = canvas.getContext('2d');
+
+ ctx.translate(50, 40);
+ ctx.rotate(Math.PI);
+ ctx.translate(-45, -45);
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ // No globalAlpha.
+ ctx.globalCompositeOperation = 'source-in';
+ ctx.shadowOffsetX = -7;
+ ctx.shadowOffsetY = 7;
+ ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
+ ctx.shadowBlur = 3;
+
+ ctx.beginLayer({filter: [
+ {name: 'dropShadow',
+ dx: 5, dy: 5, stdDeviation: 0, floodColor: '#00f'},
+ {name: 'componentTransfer',
+ funcA: {type: "table", tableValues: [0, 0.8]}}]});
+
+ 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();
+
+ const bitmap = canvas.transferToImageBitmap();
+ self.postMessage(bitmap, bitmap);
+ };
+ </script>
+ <script type="module">
+ const blob = new Blob([document.getElementById('myWorker0').textContent]);
+ const worker = new Worker(URL.createObjectURL(blob));
+ worker.addEventListener('message', msg => {
+ const outputCanvas = document.getElementById('canvas0');
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(msg.data, 0, 0);
+ if (--pending_tests == 0) {
+ document.documentElement.classList.remove('reftest-wait');
+ }
+ });
+ worker.postMessage(null);
+ </script>
+</span>
+
+<span>
+ <div>globalAlpha</div>
+ <canvas id="canvas1" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script id="myWorker1" type="text/worker">
+ self.onmessage = function(e) {
+ const canvas = new OffscreenCanvas(90, 90);
+ const ctx = canvas.getContext('2d');
+
+ ctx.translate(50, 40);
+ ctx.rotate(Math.PI);
+ ctx.translate(-45, -45);
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ ctx.globalAlpha = 0.75;
+ ctx.globalCompositeOperation = 'source-in';
+ ctx.shadowOffsetX = -7;
+ ctx.shadowOffsetY = 7;
+ ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
+ ctx.shadowBlur = 3;
+
+ ctx.beginLayer({filter: [
+ {name: 'dropShadow',
+ dx: 5, dy: 5, stdDeviation: 0, floodColor: '#00f'},
+ {name: 'componentTransfer',
+ funcA: {type: "table", tableValues: [0, 0.8]}}]});
+
+ 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();
+
+ const bitmap = canvas.transferToImageBitmap();
+ self.postMessage(bitmap, bitmap);
+ };
+ </script>
+ <script type="module">
+ const blob = new Blob([document.getElementById('myWorker1').textContent]);
+ const worker = new Worker(URL.createObjectURL(blob));
+ worker.addEventListener('message', msg => {
+ const outputCanvas = document.getElementById('canvas1');
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(msg.data, 0, 0);
+ if (--pending_tests == 0) {
+ document.documentElement.classList.remove('reftest-wait');
+ }
+ });
+ worker.postMessage(null);
+ </script>
+</span>
+
+</div>
+</html>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.composite.shadow.w.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.composite.shadow.w.html
deleted file mode 100644
index 894089d88e..0000000000
--- a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.composite.shadow.w.html
+++ /dev/null
@@ -1,58 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<html class="reftest-wait">
-<link rel="match" href="2d.layer.global-states.filter.composite.shadow-expected.html">
-<title>Canvas test: 2d.layer.global-states.filter.composite.shadow</title>
-<h1>2d.layer.global-states.filter.composite.shadow</h1>
-<p class="desc">Checks that layers with filters correctly use global render states.</p>
-<canvas id="canvas" width="200" height="200">
- <p class="fallback">FAIL (fallback content)</p>
-</canvas>
-<script id='myWorker' type='text/worker'>
- self.onmessage = function(e) {
- const canvas = new OffscreenCanvas(200, 200);
- const ctx = canvas.getContext('2d');
-
- ctx.fillStyle = 'rgba(0, 0, 255, 1)';
-
- var circle = new Path2D();
- circle.arc(90, 90, 45, 0, 2 * Math.PI);
- ctx.fill(circle);
-
- ctx.globalCompositeOperation = 'source-in';
- ctx.shadowOffsetX = -10;
- ctx.shadowOffsetY = 10;
- ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
- ctx.shadowBlur = 3;
-
- 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: 'componentTransfer',
- funcA: {type: "table", tableValues: [0, 0.7]}},
- {name: 'dropShadow', dx: 5, dy: 5, floodColor: '#81e'}]});
-
- 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.endLayer();
-
- const bitmap = canvas.transferToImageBitmap();
- self.postMessage(bitmap, bitmap);
- };
-</script>
-<script>
- const blob = new Blob([document.getElementById('myWorker').textContent]);
- const worker = new Worker(URL.createObjectURL(blob));
- worker.addEventListener('message', msg => {
- const outputCtx = document.getElementById("canvas").getContext('2d');
- outputCtx.drawImage(msg.data, 0, 0);
- document.documentElement.classList.remove("reftest-wait");
- });
- worker.postMessage(null);
-</script>
-</html>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.composite.w.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.composite.w.html
deleted file mode 100644
index 41ccdaf5c0..0000000000
--- a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.composite.w.html
+++ /dev/null
@@ -1,54 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<html class="reftest-wait">
-<link rel="match" href="2d.layer.global-states.filter.composite-expected.html">
-<title>Canvas test: 2d.layer.global-states.filter.composite</title>
-<h1>2d.layer.global-states.filter.composite</h1>
-<p class="desc">Checks that layers with filters correctly use global render states.</p>
-<canvas id="canvas" width="200" height="200">
- <p class="fallback">FAIL (fallback content)</p>
-</canvas>
-<script id='myWorker' type='text/worker'>
- self.onmessage = function(e) {
- const canvas = new OffscreenCanvas(200, 200);
- const ctx = canvas.getContext('2d');
-
- ctx.fillStyle = 'rgba(0, 0, 255, 1)';
-
- var circle = new Path2D();
- circle.arc(90, 90, 45, 0, 2 * Math.PI);
- ctx.fill(circle);
-
- ctx.globalCompositeOperation = 'source-in';
-
- 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: 'componentTransfer',
- funcA: {type: "table", tableValues: [0, 0.7]}},
- {name: 'dropShadow', dx: 5, dy: 5, floodColor: '#81e'}]});
-
- 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.endLayer();
-
- const bitmap = canvas.transferToImageBitmap();
- self.postMessage(bitmap, bitmap);
- };
-</script>
-<script>
- const blob = new Blob([document.getElementById('myWorker').textContent]);
- const worker = new Worker(URL.createObjectURL(blob));
- worker.addEventListener('message', msg => {
- const outputCtx = document.getElementById("canvas").getContext('2d');
- outputCtx.drawImage(msg.data, 0, 0);
- document.documentElement.classList.remove("reftest-wait");
- });
- worker.postMessage(null);
-</script>
-</html>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.copy.no-shadow.no-transform-expected.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.copy.no-shadow.no-transform-expected.html
new file mode 100644
index 0000000000..21aa241aca
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.copy.no-shadow.no-transform-expected.html
@@ -0,0 +1,98 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<title>Canvas test: 2d.layer.global-states.filter.copy.no-shadow.no-transform</title>
+<h1 style="font-size: 20px;">2d.layer.global-states.filter.copy.no-shadow.no-transform</h1>
+<p class="desc">Checks that layers with filters correctly use global render states.</p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(2, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>no-globalAlpha</div>
+ <canvas id="canvas0" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas0");
+ const ctx = canvas.getContext('2d');
+
+ const svg = `
+ <svg xmlns="http://www.w3.org/2000/svg"
+ width="90" height="90"
+ color-interpolation-filters="sRGB">
+ <filter id="filter" x="-100%" y="-100%" width="300%" height="300%">
+ <feDropShadow dx="5" dy="5" stdDeviation="0" flood-color="#00f" />
+ <feComponentTransfer>
+ <feFuncA type="table" tableValues="0 0.8"></feFuncA>
+ </feComponentTransfer>
+ </filter>
+ <g filter="url(#filter)">
+ <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>`;
+
+ const img = new Image();
+ img.width = 90;
+ img.height = 90;
+ img.onload = () => {
+ // No transform.
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ // No globalAlpha.
+ ctx.globalCompositeOperation = 'copy';
+ // No shadow.
+
+ ctx.drawImage(img, 0, 0);
+ };
+ img.src = 'data:image/svg+xml;base64,' + btoa(svg);
+ </script>
+</span>
+
+<span>
+ <div>globalAlpha</div>
+ <canvas id="canvas1" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas1");
+ const ctx = canvas.getContext('2d');
+
+ const svg = `
+ <svg xmlns="http://www.w3.org/2000/svg"
+ width="90" height="90"
+ color-interpolation-filters="sRGB">
+ <filter id="filter" x="-100%" y="-100%" width="300%" height="300%">
+ <feDropShadow dx="5" dy="5" stdDeviation="0" flood-color="#00f" />
+ <feComponentTransfer>
+ <feFuncA type="table" tableValues="0 0.8"></feFuncA>
+ </feComponentTransfer>
+ </filter>
+ <g filter="url(#filter)">
+ <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>`;
+
+ const img = new Image();
+ img.width = 90;
+ img.height = 90;
+ img.onload = () => {
+ // No transform.
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ ctx.globalAlpha = 0.75;
+ ctx.globalCompositeOperation = 'copy';
+ // No shadow.
+
+ ctx.drawImage(img, 0, 0);
+ };
+ img.src = 'data:image/svg+xml;base64,' + btoa(svg);
+ </script>
+</span>
+
+</div>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.copy.no-shadow.no-transform.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.copy.no-shadow.no-transform.html
new file mode 100644
index 0000000000..f08ba940af
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.copy.no-shadow.no-transform.html
@@ -0,0 +1,85 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<link rel="match" href="2d.layer.global-states.filter.copy.no-shadow.no-transform-expected.html">
+<title>Canvas test: 2d.layer.global-states.filter.copy.no-shadow.no-transform</title>
+<h1 style="font-size: 20px;">2d.layer.global-states.filter.copy.no-shadow.no-transform</h1>
+<p class="desc">Checks that layers with filters correctly use global render states.</p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(2, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>no-globalAlpha</div>
+ <canvas id="canvas0" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(90, 90);
+ const ctx = canvas.getContext('2d');
+
+ // No transform.
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ // No globalAlpha.
+ ctx.globalCompositeOperation = 'copy';
+ // No shadow.
+
+ ctx.beginLayer({filter: [
+ {name: 'dropShadow',
+ dx: 5, dy: 5, stdDeviation: 0, floodColor: '#00f'},
+ {name: 'componentTransfer',
+ funcA: {type: "table", tableValues: [0, 0.8]}}]});
+
+ 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();
+
+ const outputCanvas = document.getElementById("canvas0");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>globalAlpha</div>
+ <canvas id="canvas1" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(90, 90);
+ const ctx = canvas.getContext('2d');
+
+ // No transform.
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ ctx.globalAlpha = 0.75;
+ ctx.globalCompositeOperation = 'copy';
+ // No shadow.
+
+ ctx.beginLayer({filter: [
+ {name: 'dropShadow',
+ dx: 5, dy: 5, stdDeviation: 0, floodColor: '#00f'},
+ {name: 'componentTransfer',
+ funcA: {type: "table", tableValues: [0, 0.8]}}]});
+
+ 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();
+
+ const outputCanvas = document.getElementById("canvas1");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+</div>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.copy.no-shadow.no-transform.w.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.copy.no-shadow.no-transform.w.html
new file mode 100644
index 0000000000..75fc90bae6
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.copy.no-shadow.no-transform.w.html
@@ -0,0 +1,116 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<html class="reftest-wait">
+<link rel="match" href="2d.layer.global-states.filter.copy.no-shadow.no-transform-expected.html">
+<title>Canvas test: 2d.layer.global-states.filter.copy.no-shadow.no-transform</title>
+<h1 style="font-size: 20px;">2d.layer.global-states.filter.copy.no-shadow.no-transform</h1>
+<p class="desc">Checks that layers with filters correctly use global render states.</p>
+<script>pending_tests = 2;</script>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(2, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>no-globalAlpha</div>
+ <canvas id="canvas0" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script id="myWorker0" type="text/worker">
+ self.onmessage = function(e) {
+ const canvas = new OffscreenCanvas(90, 90);
+ const ctx = canvas.getContext('2d');
+
+ // No transform.
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ // No globalAlpha.
+ ctx.globalCompositeOperation = 'copy';
+ // No shadow.
+
+ ctx.beginLayer({filter: [
+ {name: 'dropShadow',
+ dx: 5, dy: 5, stdDeviation: 0, floodColor: '#00f'},
+ {name: 'componentTransfer',
+ funcA: {type: "table", tableValues: [0, 0.8]}}]});
+
+ 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();
+
+ const bitmap = canvas.transferToImageBitmap();
+ self.postMessage(bitmap, bitmap);
+ };
+ </script>
+ <script type="module">
+ const blob = new Blob([document.getElementById('myWorker0').textContent]);
+ const worker = new Worker(URL.createObjectURL(blob));
+ worker.addEventListener('message', msg => {
+ const outputCanvas = document.getElementById('canvas0');
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(msg.data, 0, 0);
+ if (--pending_tests == 0) {
+ document.documentElement.classList.remove('reftest-wait');
+ }
+ });
+ worker.postMessage(null);
+ </script>
+</span>
+
+<span>
+ <div>globalAlpha</div>
+ <canvas id="canvas1" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script id="myWorker1" type="text/worker">
+ self.onmessage = function(e) {
+ const canvas = new OffscreenCanvas(90, 90);
+ const ctx = canvas.getContext('2d');
+
+ // No transform.
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ ctx.globalAlpha = 0.75;
+ ctx.globalCompositeOperation = 'copy';
+ // No shadow.
+
+ ctx.beginLayer({filter: [
+ {name: 'dropShadow',
+ dx: 5, dy: 5, stdDeviation: 0, floodColor: '#00f'},
+ {name: 'componentTransfer',
+ funcA: {type: "table", tableValues: [0, 0.8]}}]});
+
+ 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();
+
+ const bitmap = canvas.transferToImageBitmap();
+ self.postMessage(bitmap, bitmap);
+ };
+ </script>
+ <script type="module">
+ const blob = new Blob([document.getElementById('myWorker1').textContent]);
+ const worker = new Worker(URL.createObjectURL(blob));
+ worker.addEventListener('message', msg => {
+ const outputCanvas = document.getElementById('canvas1');
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(msg.data, 0, 0);
+ if (--pending_tests == 0) {
+ document.documentElement.classList.remove('reftest-wait');
+ }
+ });
+ worker.postMessage(null);
+ </script>
+</span>
+
+</div>
+</html>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.copy.no-shadow.rotation-expected.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.copy.no-shadow.rotation-expected.html
new file mode 100644
index 0000000000..b2b46ee039
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.copy.no-shadow.rotation-expected.html
@@ -0,0 +1,102 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<title>Canvas test: 2d.layer.global-states.filter.copy.no-shadow.rotation</title>
+<h1 style="font-size: 20px;">2d.layer.global-states.filter.copy.no-shadow.rotation</h1>
+<p class="desc">Checks that layers with filters correctly use global render states.</p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(2, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>no-globalAlpha</div>
+ <canvas id="canvas0" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas0");
+ const ctx = canvas.getContext('2d');
+
+ const svg = `
+ <svg xmlns="http://www.w3.org/2000/svg"
+ width="90" height="90"
+ color-interpolation-filters="sRGB">
+ <filter id="filter" x="-100%" y="-100%" width="300%" height="300%">
+ <feDropShadow dx="5" dy="5" stdDeviation="0" flood-color="#00f" />
+ <feComponentTransfer>
+ <feFuncA type="table" tableValues="0 0.8"></feFuncA>
+ </feComponentTransfer>
+ </filter>
+ <g filter="url(#filter)">
+ <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>`;
+
+ const img = new Image();
+ img.width = 90;
+ img.height = 90;
+ img.onload = () => {
+ ctx.translate(50, 40);
+ ctx.rotate(Math.PI);
+ ctx.translate(-45, -45);
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ // No globalAlpha.
+ ctx.globalCompositeOperation = 'copy';
+ // No shadow.
+
+ ctx.drawImage(img, 0, 0);
+ };
+ img.src = 'data:image/svg+xml;base64,' + btoa(svg);
+ </script>
+</span>
+
+<span>
+ <div>globalAlpha</div>
+ <canvas id="canvas1" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas1");
+ const ctx = canvas.getContext('2d');
+
+ const svg = `
+ <svg xmlns="http://www.w3.org/2000/svg"
+ width="90" height="90"
+ color-interpolation-filters="sRGB">
+ <filter id="filter" x="-100%" y="-100%" width="300%" height="300%">
+ <feDropShadow dx="5" dy="5" stdDeviation="0" flood-color="#00f" />
+ <feComponentTransfer>
+ <feFuncA type="table" tableValues="0 0.8"></feFuncA>
+ </feComponentTransfer>
+ </filter>
+ <g filter="url(#filter)">
+ <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>`;
+
+ const img = new Image();
+ img.width = 90;
+ img.height = 90;
+ img.onload = () => {
+ ctx.translate(50, 40);
+ ctx.rotate(Math.PI);
+ ctx.translate(-45, -45);
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ ctx.globalAlpha = 0.75;
+ ctx.globalCompositeOperation = 'copy';
+ // No shadow.
+
+ ctx.drawImage(img, 0, 0);
+ };
+ img.src = 'data:image/svg+xml;base64,' + btoa(svg);
+ </script>
+</span>
+
+</div>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.copy.no-shadow.rotation.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.copy.no-shadow.rotation.html
new file mode 100644
index 0000000000..3f12cf0c4e
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.copy.no-shadow.rotation.html
@@ -0,0 +1,89 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<link rel="match" href="2d.layer.global-states.filter.copy.no-shadow.rotation-expected.html">
+<title>Canvas test: 2d.layer.global-states.filter.copy.no-shadow.rotation</title>
+<h1 style="font-size: 20px;">2d.layer.global-states.filter.copy.no-shadow.rotation</h1>
+<p class="desc">Checks that layers with filters correctly use global render states.</p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(2, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>no-globalAlpha</div>
+ <canvas id="canvas0" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(90, 90);
+ const ctx = canvas.getContext('2d');
+
+ ctx.translate(50, 40);
+ ctx.rotate(Math.PI);
+ ctx.translate(-45, -45);
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ // No globalAlpha.
+ ctx.globalCompositeOperation = 'copy';
+ // No shadow.
+
+ ctx.beginLayer({filter: [
+ {name: 'dropShadow',
+ dx: 5, dy: 5, stdDeviation: 0, floodColor: '#00f'},
+ {name: 'componentTransfer',
+ funcA: {type: "table", tableValues: [0, 0.8]}}]});
+
+ 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();
+
+ const outputCanvas = document.getElementById("canvas0");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>globalAlpha</div>
+ <canvas id="canvas1" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(90, 90);
+ const ctx = canvas.getContext('2d');
+
+ ctx.translate(50, 40);
+ ctx.rotate(Math.PI);
+ ctx.translate(-45, -45);
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ ctx.globalAlpha = 0.75;
+ ctx.globalCompositeOperation = 'copy';
+ // No shadow.
+
+ ctx.beginLayer({filter: [
+ {name: 'dropShadow',
+ dx: 5, dy: 5, stdDeviation: 0, floodColor: '#00f'},
+ {name: 'componentTransfer',
+ funcA: {type: "table", tableValues: [0, 0.8]}}]});
+
+ 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();
+
+ const outputCanvas = document.getElementById("canvas1");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+</div>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.copy.no-shadow.rotation.w.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.copy.no-shadow.rotation.w.html
new file mode 100644
index 0000000000..0a3ecee669
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.copy.no-shadow.rotation.w.html
@@ -0,0 +1,120 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<html class="reftest-wait">
+<link rel="match" href="2d.layer.global-states.filter.copy.no-shadow.rotation-expected.html">
+<title>Canvas test: 2d.layer.global-states.filter.copy.no-shadow.rotation</title>
+<h1 style="font-size: 20px;">2d.layer.global-states.filter.copy.no-shadow.rotation</h1>
+<p class="desc">Checks that layers with filters correctly use global render states.</p>
+<script>pending_tests = 2;</script>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(2, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>no-globalAlpha</div>
+ <canvas id="canvas0" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script id="myWorker0" type="text/worker">
+ self.onmessage = function(e) {
+ const canvas = new OffscreenCanvas(90, 90);
+ const ctx = canvas.getContext('2d');
+
+ ctx.translate(50, 40);
+ ctx.rotate(Math.PI);
+ ctx.translate(-45, -45);
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ // No globalAlpha.
+ ctx.globalCompositeOperation = 'copy';
+ // No shadow.
+
+ ctx.beginLayer({filter: [
+ {name: 'dropShadow',
+ dx: 5, dy: 5, stdDeviation: 0, floodColor: '#00f'},
+ {name: 'componentTransfer',
+ funcA: {type: "table", tableValues: [0, 0.8]}}]});
+
+ 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();
+
+ const bitmap = canvas.transferToImageBitmap();
+ self.postMessage(bitmap, bitmap);
+ };
+ </script>
+ <script type="module">
+ const blob = new Blob([document.getElementById('myWorker0').textContent]);
+ const worker = new Worker(URL.createObjectURL(blob));
+ worker.addEventListener('message', msg => {
+ const outputCanvas = document.getElementById('canvas0');
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(msg.data, 0, 0);
+ if (--pending_tests == 0) {
+ document.documentElement.classList.remove('reftest-wait');
+ }
+ });
+ worker.postMessage(null);
+ </script>
+</span>
+
+<span>
+ <div>globalAlpha</div>
+ <canvas id="canvas1" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script id="myWorker1" type="text/worker">
+ self.onmessage = function(e) {
+ const canvas = new OffscreenCanvas(90, 90);
+ const ctx = canvas.getContext('2d');
+
+ ctx.translate(50, 40);
+ ctx.rotate(Math.PI);
+ ctx.translate(-45, -45);
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ ctx.globalAlpha = 0.75;
+ ctx.globalCompositeOperation = 'copy';
+ // No shadow.
+
+ ctx.beginLayer({filter: [
+ {name: 'dropShadow',
+ dx: 5, dy: 5, stdDeviation: 0, floodColor: '#00f'},
+ {name: 'componentTransfer',
+ funcA: {type: "table", tableValues: [0, 0.8]}}]});
+
+ 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();
+
+ const bitmap = canvas.transferToImageBitmap();
+ self.postMessage(bitmap, bitmap);
+ };
+ </script>
+ <script type="module">
+ const blob = new Blob([document.getElementById('myWorker1').textContent]);
+ const worker = new Worker(URL.createObjectURL(blob));
+ worker.addEventListener('message', msg => {
+ const outputCanvas = document.getElementById('canvas1');
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(msg.data, 0, 0);
+ if (--pending_tests == 0) {
+ document.documentElement.classList.remove('reftest-wait');
+ }
+ });
+ worker.postMessage(null);
+ </script>
+</span>
+
+</div>
+</html>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.copy.shadow.no-transform-expected.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.copy.shadow.no-transform-expected.html
new file mode 100644
index 0000000000..d11326d5d6
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.copy.shadow.no-transform-expected.html
@@ -0,0 +1,104 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<title>Canvas test: 2d.layer.global-states.filter.copy.shadow.no-transform</title>
+<h1 style="font-size: 20px;">2d.layer.global-states.filter.copy.shadow.no-transform</h1>
+<p class="desc">Checks that layers with filters correctly use global render states.</p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(2, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>no-globalAlpha</div>
+ <canvas id="canvas0" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas0");
+ const ctx = canvas.getContext('2d');
+
+ const svg = `
+ <svg xmlns="http://www.w3.org/2000/svg"
+ width="90" height="90"
+ color-interpolation-filters="sRGB">
+ <filter id="filter" x="-100%" y="-100%" width="300%" height="300%">
+ <feDropShadow dx="5" dy="5" stdDeviation="0" flood-color="#00f" />
+ <feComponentTransfer>
+ <feFuncA type="table" tableValues="0 0.8"></feFuncA>
+ </feComponentTransfer>
+ </filter>
+ <g filter="url(#filter)">
+ <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>`;
+
+ const img = new Image();
+ img.width = 90;
+ img.height = 90;
+ img.onload = () => {
+ // No transform.
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ // No globalAlpha.
+ ctx.globalCompositeOperation = 'copy';
+ ctx.shadowOffsetX = -7;
+ ctx.shadowOffsetY = 7;
+ ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
+ ctx.shadowBlur = 3;
+
+ ctx.drawImage(img, 0, 0);
+ };
+ img.src = 'data:image/svg+xml;base64,' + btoa(svg);
+ </script>
+</span>
+
+<span>
+ <div>globalAlpha</div>
+ <canvas id="canvas1" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas1");
+ const ctx = canvas.getContext('2d');
+
+ const svg = `
+ <svg xmlns="http://www.w3.org/2000/svg"
+ width="90" height="90"
+ color-interpolation-filters="sRGB">
+ <filter id="filter" x="-100%" y="-100%" width="300%" height="300%">
+ <feDropShadow dx="5" dy="5" stdDeviation="0" flood-color="#00f" />
+ <feComponentTransfer>
+ <feFuncA type="table" tableValues="0 0.8"></feFuncA>
+ </feComponentTransfer>
+ </filter>
+ <g filter="url(#filter)">
+ <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>`;
+
+ const img = new Image();
+ img.width = 90;
+ img.height = 90;
+ img.onload = () => {
+ // No transform.
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ ctx.globalAlpha = 0.75;
+ ctx.globalCompositeOperation = 'copy';
+ ctx.shadowOffsetX = -7;
+ ctx.shadowOffsetY = 7;
+ ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
+ ctx.shadowBlur = 3;
+
+ ctx.drawImage(img, 0, 0);
+ };
+ img.src = 'data:image/svg+xml;base64,' + btoa(svg);
+ </script>
+</span>
+
+</div>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.copy.shadow.no-transform.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.copy.shadow.no-transform.html
new file mode 100644
index 0000000000..b4996deb6f
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.copy.shadow.no-transform.html
@@ -0,0 +1,91 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<link rel="match" href="2d.layer.global-states.filter.copy.shadow.no-transform-expected.html">
+<title>Canvas test: 2d.layer.global-states.filter.copy.shadow.no-transform</title>
+<h1 style="font-size: 20px;">2d.layer.global-states.filter.copy.shadow.no-transform</h1>
+<p class="desc">Checks that layers with filters correctly use global render states.</p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(2, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>no-globalAlpha</div>
+ <canvas id="canvas0" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(90, 90);
+ const ctx = canvas.getContext('2d');
+
+ // No transform.
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ // No globalAlpha.
+ ctx.globalCompositeOperation = 'copy';
+ ctx.shadowOffsetX = -7;
+ ctx.shadowOffsetY = 7;
+ ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
+ ctx.shadowBlur = 3;
+
+ ctx.beginLayer({filter: [
+ {name: 'dropShadow',
+ dx: 5, dy: 5, stdDeviation: 0, floodColor: '#00f'},
+ {name: 'componentTransfer',
+ funcA: {type: "table", tableValues: [0, 0.8]}}]});
+
+ 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();
+
+ const outputCanvas = document.getElementById("canvas0");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>globalAlpha</div>
+ <canvas id="canvas1" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(90, 90);
+ const ctx = canvas.getContext('2d');
+
+ // No transform.
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ ctx.globalAlpha = 0.75;
+ ctx.globalCompositeOperation = 'copy';
+ ctx.shadowOffsetX = -7;
+ ctx.shadowOffsetY = 7;
+ ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
+ ctx.shadowBlur = 3;
+
+ ctx.beginLayer({filter: [
+ {name: 'dropShadow',
+ dx: 5, dy: 5, stdDeviation: 0, floodColor: '#00f'},
+ {name: 'componentTransfer',
+ funcA: {type: "table", tableValues: [0, 0.8]}}]});
+
+ 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();
+
+ const outputCanvas = document.getElementById("canvas1");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+</div>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.copy.shadow.no-transform.w.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.copy.shadow.no-transform.w.html
new file mode 100644
index 0000000000..9c13a367b3
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.copy.shadow.no-transform.w.html
@@ -0,0 +1,122 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<html class="reftest-wait">
+<link rel="match" href="2d.layer.global-states.filter.copy.shadow.no-transform-expected.html">
+<title>Canvas test: 2d.layer.global-states.filter.copy.shadow.no-transform</title>
+<h1 style="font-size: 20px;">2d.layer.global-states.filter.copy.shadow.no-transform</h1>
+<p class="desc">Checks that layers with filters correctly use global render states.</p>
+<script>pending_tests = 2;</script>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(2, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>no-globalAlpha</div>
+ <canvas id="canvas0" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script id="myWorker0" type="text/worker">
+ self.onmessage = function(e) {
+ const canvas = new OffscreenCanvas(90, 90);
+ const ctx = canvas.getContext('2d');
+
+ // No transform.
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ // No globalAlpha.
+ ctx.globalCompositeOperation = 'copy';
+ ctx.shadowOffsetX = -7;
+ ctx.shadowOffsetY = 7;
+ ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
+ ctx.shadowBlur = 3;
+
+ ctx.beginLayer({filter: [
+ {name: 'dropShadow',
+ dx: 5, dy: 5, stdDeviation: 0, floodColor: '#00f'},
+ {name: 'componentTransfer',
+ funcA: {type: "table", tableValues: [0, 0.8]}}]});
+
+ 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();
+
+ const bitmap = canvas.transferToImageBitmap();
+ self.postMessage(bitmap, bitmap);
+ };
+ </script>
+ <script type="module">
+ const blob = new Blob([document.getElementById('myWorker0').textContent]);
+ const worker = new Worker(URL.createObjectURL(blob));
+ worker.addEventListener('message', msg => {
+ const outputCanvas = document.getElementById('canvas0');
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(msg.data, 0, 0);
+ if (--pending_tests == 0) {
+ document.documentElement.classList.remove('reftest-wait');
+ }
+ });
+ worker.postMessage(null);
+ </script>
+</span>
+
+<span>
+ <div>globalAlpha</div>
+ <canvas id="canvas1" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script id="myWorker1" type="text/worker">
+ self.onmessage = function(e) {
+ const canvas = new OffscreenCanvas(90, 90);
+ const ctx = canvas.getContext('2d');
+
+ // No transform.
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ ctx.globalAlpha = 0.75;
+ ctx.globalCompositeOperation = 'copy';
+ ctx.shadowOffsetX = -7;
+ ctx.shadowOffsetY = 7;
+ ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
+ ctx.shadowBlur = 3;
+
+ ctx.beginLayer({filter: [
+ {name: 'dropShadow',
+ dx: 5, dy: 5, stdDeviation: 0, floodColor: '#00f'},
+ {name: 'componentTransfer',
+ funcA: {type: "table", tableValues: [0, 0.8]}}]});
+
+ 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();
+
+ const bitmap = canvas.transferToImageBitmap();
+ self.postMessage(bitmap, bitmap);
+ };
+ </script>
+ <script type="module">
+ const blob = new Blob([document.getElementById('myWorker1').textContent]);
+ const worker = new Worker(URL.createObjectURL(blob));
+ worker.addEventListener('message', msg => {
+ const outputCanvas = document.getElementById('canvas1');
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(msg.data, 0, 0);
+ if (--pending_tests == 0) {
+ document.documentElement.classList.remove('reftest-wait');
+ }
+ });
+ worker.postMessage(null);
+ </script>
+</span>
+
+</div>
+</html>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.copy.shadow.rotation-expected.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.copy.shadow.rotation-expected.html
new file mode 100644
index 0000000000..3ac098c344
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.copy.shadow.rotation-expected.html
@@ -0,0 +1,108 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<title>Canvas test: 2d.layer.global-states.filter.copy.shadow.rotation</title>
+<h1 style="font-size: 20px;">2d.layer.global-states.filter.copy.shadow.rotation</h1>
+<p class="desc">Checks that layers with filters correctly use global render states.</p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(2, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>no-globalAlpha</div>
+ <canvas id="canvas0" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas0");
+ const ctx = canvas.getContext('2d');
+
+ const svg = `
+ <svg xmlns="http://www.w3.org/2000/svg"
+ width="90" height="90"
+ color-interpolation-filters="sRGB">
+ <filter id="filter" x="-100%" y="-100%" width="300%" height="300%">
+ <feDropShadow dx="5" dy="5" stdDeviation="0" flood-color="#00f" />
+ <feComponentTransfer>
+ <feFuncA type="table" tableValues="0 0.8"></feFuncA>
+ </feComponentTransfer>
+ </filter>
+ <g filter="url(#filter)">
+ <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>`;
+
+ const img = new Image();
+ img.width = 90;
+ img.height = 90;
+ img.onload = () => {
+ ctx.translate(50, 40);
+ ctx.rotate(Math.PI);
+ ctx.translate(-45, -45);
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ // No globalAlpha.
+ ctx.globalCompositeOperation = 'copy';
+ ctx.shadowOffsetX = -7;
+ ctx.shadowOffsetY = 7;
+ ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
+ ctx.shadowBlur = 3;
+
+ ctx.drawImage(img, 0, 0);
+ };
+ img.src = 'data:image/svg+xml;base64,' + btoa(svg);
+ </script>
+</span>
+
+<span>
+ <div>globalAlpha</div>
+ <canvas id="canvas1" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas1");
+ const ctx = canvas.getContext('2d');
+
+ const svg = `
+ <svg xmlns="http://www.w3.org/2000/svg"
+ width="90" height="90"
+ color-interpolation-filters="sRGB">
+ <filter id="filter" x="-100%" y="-100%" width="300%" height="300%">
+ <feDropShadow dx="5" dy="5" stdDeviation="0" flood-color="#00f" />
+ <feComponentTransfer>
+ <feFuncA type="table" tableValues="0 0.8"></feFuncA>
+ </feComponentTransfer>
+ </filter>
+ <g filter="url(#filter)">
+ <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>`;
+
+ const img = new Image();
+ img.width = 90;
+ img.height = 90;
+ img.onload = () => {
+ ctx.translate(50, 40);
+ ctx.rotate(Math.PI);
+ ctx.translate(-45, -45);
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ ctx.globalAlpha = 0.75;
+ ctx.globalCompositeOperation = 'copy';
+ ctx.shadowOffsetX = -7;
+ ctx.shadowOffsetY = 7;
+ ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
+ ctx.shadowBlur = 3;
+
+ ctx.drawImage(img, 0, 0);
+ };
+ img.src = 'data:image/svg+xml;base64,' + btoa(svg);
+ </script>
+</span>
+
+</div>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.copy.shadow.rotation.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.copy.shadow.rotation.html
new file mode 100644
index 0000000000..eab5f8312b
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.copy.shadow.rotation.html
@@ -0,0 +1,95 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<link rel="match" href="2d.layer.global-states.filter.copy.shadow.rotation-expected.html">
+<title>Canvas test: 2d.layer.global-states.filter.copy.shadow.rotation</title>
+<h1 style="font-size: 20px;">2d.layer.global-states.filter.copy.shadow.rotation</h1>
+<p class="desc">Checks that layers with filters correctly use global render states.</p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(2, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>no-globalAlpha</div>
+ <canvas id="canvas0" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(90, 90);
+ const ctx = canvas.getContext('2d');
+
+ ctx.translate(50, 40);
+ ctx.rotate(Math.PI);
+ ctx.translate(-45, -45);
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ // No globalAlpha.
+ ctx.globalCompositeOperation = 'copy';
+ ctx.shadowOffsetX = -7;
+ ctx.shadowOffsetY = 7;
+ ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
+ ctx.shadowBlur = 3;
+
+ ctx.beginLayer({filter: [
+ {name: 'dropShadow',
+ dx: 5, dy: 5, stdDeviation: 0, floodColor: '#00f'},
+ {name: 'componentTransfer',
+ funcA: {type: "table", tableValues: [0, 0.8]}}]});
+
+ 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();
+
+ const outputCanvas = document.getElementById("canvas0");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>globalAlpha</div>
+ <canvas id="canvas1" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(90, 90);
+ const ctx = canvas.getContext('2d');
+
+ ctx.translate(50, 40);
+ ctx.rotate(Math.PI);
+ ctx.translate(-45, -45);
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ ctx.globalAlpha = 0.75;
+ ctx.globalCompositeOperation = 'copy';
+ ctx.shadowOffsetX = -7;
+ ctx.shadowOffsetY = 7;
+ ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
+ ctx.shadowBlur = 3;
+
+ ctx.beginLayer({filter: [
+ {name: 'dropShadow',
+ dx: 5, dy: 5, stdDeviation: 0, floodColor: '#00f'},
+ {name: 'componentTransfer',
+ funcA: {type: "table", tableValues: [0, 0.8]}}]});
+
+ 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();
+
+ const outputCanvas = document.getElementById("canvas1");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+</div>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.copy.shadow.rotation.w.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.copy.shadow.rotation.w.html
new file mode 100644
index 0000000000..aebd6cc00d
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.copy.shadow.rotation.w.html
@@ -0,0 +1,126 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<html class="reftest-wait">
+<link rel="match" href="2d.layer.global-states.filter.copy.shadow.rotation-expected.html">
+<title>Canvas test: 2d.layer.global-states.filter.copy.shadow.rotation</title>
+<h1 style="font-size: 20px;">2d.layer.global-states.filter.copy.shadow.rotation</h1>
+<p class="desc">Checks that layers with filters correctly use global render states.</p>
+<script>pending_tests = 2;</script>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(2, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>no-globalAlpha</div>
+ <canvas id="canvas0" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script id="myWorker0" type="text/worker">
+ self.onmessage = function(e) {
+ const canvas = new OffscreenCanvas(90, 90);
+ const ctx = canvas.getContext('2d');
+
+ ctx.translate(50, 40);
+ ctx.rotate(Math.PI);
+ ctx.translate(-45, -45);
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ // No globalAlpha.
+ ctx.globalCompositeOperation = 'copy';
+ ctx.shadowOffsetX = -7;
+ ctx.shadowOffsetY = 7;
+ ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
+ ctx.shadowBlur = 3;
+
+ ctx.beginLayer({filter: [
+ {name: 'dropShadow',
+ dx: 5, dy: 5, stdDeviation: 0, floodColor: '#00f'},
+ {name: 'componentTransfer',
+ funcA: {type: "table", tableValues: [0, 0.8]}}]});
+
+ 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();
+
+ const bitmap = canvas.transferToImageBitmap();
+ self.postMessage(bitmap, bitmap);
+ };
+ </script>
+ <script type="module">
+ const blob = new Blob([document.getElementById('myWorker0').textContent]);
+ const worker = new Worker(URL.createObjectURL(blob));
+ worker.addEventListener('message', msg => {
+ const outputCanvas = document.getElementById('canvas0');
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(msg.data, 0, 0);
+ if (--pending_tests == 0) {
+ document.documentElement.classList.remove('reftest-wait');
+ }
+ });
+ worker.postMessage(null);
+ </script>
+</span>
+
+<span>
+ <div>globalAlpha</div>
+ <canvas id="canvas1" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script id="myWorker1" type="text/worker">
+ self.onmessage = function(e) {
+ const canvas = new OffscreenCanvas(90, 90);
+ const ctx = canvas.getContext('2d');
+
+ ctx.translate(50, 40);
+ ctx.rotate(Math.PI);
+ ctx.translate(-45, -45);
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ ctx.globalAlpha = 0.75;
+ ctx.globalCompositeOperation = 'copy';
+ ctx.shadowOffsetX = -7;
+ ctx.shadowOffsetY = 7;
+ ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
+ ctx.shadowBlur = 3;
+
+ ctx.beginLayer({filter: [
+ {name: 'dropShadow',
+ dx: 5, dy: 5, stdDeviation: 0, floodColor: '#00f'},
+ {name: 'componentTransfer',
+ funcA: {type: "table", tableValues: [0, 0.8]}}]});
+
+ 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();
+
+ const bitmap = canvas.transferToImageBitmap();
+ self.postMessage(bitmap, bitmap);
+ };
+ </script>
+ <script type="module">
+ const blob = new Blob([document.getElementById('myWorker1').textContent]);
+ const worker = new Worker(URL.createObjectURL(blob));
+ worker.addEventListener('message', msg => {
+ const outputCanvas = document.getElementById('canvas1');
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(msg.data, 0, 0);
+ if (--pending_tests == 0) {
+ document.documentElement.classList.remove('reftest-wait');
+ }
+ });
+ worker.postMessage(null);
+ </script>
+</span>
+
+</div>
+</html>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.no-composite-op.no-shadow.no-transform-expected.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.no-composite-op.no-shadow.no-transform-expected.html
new file mode 100644
index 0000000000..a445ae2c4a
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.no-composite-op.no-shadow.no-transform-expected.html
@@ -0,0 +1,98 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<title>Canvas test: 2d.layer.global-states.filter.no-composite-op.no-shadow.no-transform</title>
+<h1 style="font-size: 20px;">2d.layer.global-states.filter.no-composite-op.no-shadow.no-transform</h1>
+<p class="desc">Checks that layers with filters correctly use global render states.</p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(2, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>no-globalAlpha</div>
+ <canvas id="canvas0" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas0");
+ const ctx = canvas.getContext('2d');
+
+ const svg = `
+ <svg xmlns="http://www.w3.org/2000/svg"
+ width="90" height="90"
+ color-interpolation-filters="sRGB">
+ <filter id="filter" x="-100%" y="-100%" width="300%" height="300%">
+ <feDropShadow dx="5" dy="5" stdDeviation="0" flood-color="#00f" />
+ <feComponentTransfer>
+ <feFuncA type="table" tableValues="0 0.8"></feFuncA>
+ </feComponentTransfer>
+ </filter>
+ <g filter="url(#filter)">
+ <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>`;
+
+ const img = new Image();
+ img.width = 90;
+ img.height = 90;
+ img.onload = () => {
+ // No transform.
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ // No globalAlpha.
+ // No globalCompositeOperation.
+ // No shadow.
+
+ ctx.drawImage(img, 0, 0);
+ };
+ img.src = 'data:image/svg+xml;base64,' + btoa(svg);
+ </script>
+</span>
+
+<span>
+ <div>globalAlpha</div>
+ <canvas id="canvas1" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas1");
+ const ctx = canvas.getContext('2d');
+
+ const svg = `
+ <svg xmlns="http://www.w3.org/2000/svg"
+ width="90" height="90"
+ color-interpolation-filters="sRGB">
+ <filter id="filter" x="-100%" y="-100%" width="300%" height="300%">
+ <feDropShadow dx="5" dy="5" stdDeviation="0" flood-color="#00f" />
+ <feComponentTransfer>
+ <feFuncA type="table" tableValues="0 0.8"></feFuncA>
+ </feComponentTransfer>
+ </filter>
+ <g filter="url(#filter)">
+ <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>`;
+
+ const img = new Image();
+ img.width = 90;
+ img.height = 90;
+ img.onload = () => {
+ // No transform.
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ ctx.globalAlpha = 0.75;
+ // No globalCompositeOperation.
+ // No shadow.
+
+ ctx.drawImage(img, 0, 0);
+ };
+ img.src = 'data:image/svg+xml;base64,' + btoa(svg);
+ </script>
+</span>
+
+</div>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.no-composite-op.no-shadow.no-transform.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.no-composite-op.no-shadow.no-transform.html
new file mode 100644
index 0000000000..f86b0fd37d
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.no-composite-op.no-shadow.no-transform.html
@@ -0,0 +1,85 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<link rel="match" href="2d.layer.global-states.filter.no-composite-op.no-shadow.no-transform-expected.html">
+<title>Canvas test: 2d.layer.global-states.filter.no-composite-op.no-shadow.no-transform</title>
+<h1 style="font-size: 20px;">2d.layer.global-states.filter.no-composite-op.no-shadow.no-transform</h1>
+<p class="desc">Checks that layers with filters correctly use global render states.</p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(2, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>no-globalAlpha</div>
+ <canvas id="canvas0" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(90, 90);
+ const ctx = canvas.getContext('2d');
+
+ // No transform.
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ // No globalAlpha.
+ // No globalCompositeOperation.
+ // No shadow.
+
+ ctx.beginLayer({filter: [
+ {name: 'dropShadow',
+ dx: 5, dy: 5, stdDeviation: 0, floodColor: '#00f'},
+ {name: 'componentTransfer',
+ funcA: {type: "table", tableValues: [0, 0.8]}}]});
+
+ 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();
+
+ const outputCanvas = document.getElementById("canvas0");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>globalAlpha</div>
+ <canvas id="canvas1" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(90, 90);
+ const ctx = canvas.getContext('2d');
+
+ // No transform.
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ ctx.globalAlpha = 0.75;
+ // No globalCompositeOperation.
+ // No shadow.
+
+ ctx.beginLayer({filter: [
+ {name: 'dropShadow',
+ dx: 5, dy: 5, stdDeviation: 0, floodColor: '#00f'},
+ {name: 'componentTransfer',
+ funcA: {type: "table", tableValues: [0, 0.8]}}]});
+
+ 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();
+
+ const outputCanvas = document.getElementById("canvas1");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+</div>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.no-composite-op.no-shadow.no-transform.w.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.no-composite-op.no-shadow.no-transform.w.html
new file mode 100644
index 0000000000..ab0836af94
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.no-composite-op.no-shadow.no-transform.w.html
@@ -0,0 +1,116 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<html class="reftest-wait">
+<link rel="match" href="2d.layer.global-states.filter.no-composite-op.no-shadow.no-transform-expected.html">
+<title>Canvas test: 2d.layer.global-states.filter.no-composite-op.no-shadow.no-transform</title>
+<h1 style="font-size: 20px;">2d.layer.global-states.filter.no-composite-op.no-shadow.no-transform</h1>
+<p class="desc">Checks that layers with filters correctly use global render states.</p>
+<script>pending_tests = 2;</script>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(2, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>no-globalAlpha</div>
+ <canvas id="canvas0" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script id="myWorker0" type="text/worker">
+ self.onmessage = function(e) {
+ const canvas = new OffscreenCanvas(90, 90);
+ const ctx = canvas.getContext('2d');
+
+ // No transform.
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ // No globalAlpha.
+ // No globalCompositeOperation.
+ // No shadow.
+
+ ctx.beginLayer({filter: [
+ {name: 'dropShadow',
+ dx: 5, dy: 5, stdDeviation: 0, floodColor: '#00f'},
+ {name: 'componentTransfer',
+ funcA: {type: "table", tableValues: [0, 0.8]}}]});
+
+ 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();
+
+ const bitmap = canvas.transferToImageBitmap();
+ self.postMessage(bitmap, bitmap);
+ };
+ </script>
+ <script type="module">
+ const blob = new Blob([document.getElementById('myWorker0').textContent]);
+ const worker = new Worker(URL.createObjectURL(blob));
+ worker.addEventListener('message', msg => {
+ const outputCanvas = document.getElementById('canvas0');
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(msg.data, 0, 0);
+ if (--pending_tests == 0) {
+ document.documentElement.classList.remove('reftest-wait');
+ }
+ });
+ worker.postMessage(null);
+ </script>
+</span>
+
+<span>
+ <div>globalAlpha</div>
+ <canvas id="canvas1" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script id="myWorker1" type="text/worker">
+ self.onmessage = function(e) {
+ const canvas = new OffscreenCanvas(90, 90);
+ const ctx = canvas.getContext('2d');
+
+ // No transform.
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ ctx.globalAlpha = 0.75;
+ // No globalCompositeOperation.
+ // No shadow.
+
+ ctx.beginLayer({filter: [
+ {name: 'dropShadow',
+ dx: 5, dy: 5, stdDeviation: 0, floodColor: '#00f'},
+ {name: 'componentTransfer',
+ funcA: {type: "table", tableValues: [0, 0.8]}}]});
+
+ 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();
+
+ const bitmap = canvas.transferToImageBitmap();
+ self.postMessage(bitmap, bitmap);
+ };
+ </script>
+ <script type="module">
+ const blob = new Blob([document.getElementById('myWorker1').textContent]);
+ const worker = new Worker(URL.createObjectURL(blob));
+ worker.addEventListener('message', msg => {
+ const outputCanvas = document.getElementById('canvas1');
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(msg.data, 0, 0);
+ if (--pending_tests == 0) {
+ document.documentElement.classList.remove('reftest-wait');
+ }
+ });
+ worker.postMessage(null);
+ </script>
+</span>
+
+</div>
+</html>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.no-composite-op.no-shadow.rotation-expected.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.no-composite-op.no-shadow.rotation-expected.html
new file mode 100644
index 0000000000..610c601b1c
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.no-composite-op.no-shadow.rotation-expected.html
@@ -0,0 +1,102 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<title>Canvas test: 2d.layer.global-states.filter.no-composite-op.no-shadow.rotation</title>
+<h1 style="font-size: 20px;">2d.layer.global-states.filter.no-composite-op.no-shadow.rotation</h1>
+<p class="desc">Checks that layers with filters correctly use global render states.</p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(2, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>no-globalAlpha</div>
+ <canvas id="canvas0" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas0");
+ const ctx = canvas.getContext('2d');
+
+ const svg = `
+ <svg xmlns="http://www.w3.org/2000/svg"
+ width="90" height="90"
+ color-interpolation-filters="sRGB">
+ <filter id="filter" x="-100%" y="-100%" width="300%" height="300%">
+ <feDropShadow dx="5" dy="5" stdDeviation="0" flood-color="#00f" />
+ <feComponentTransfer>
+ <feFuncA type="table" tableValues="0 0.8"></feFuncA>
+ </feComponentTransfer>
+ </filter>
+ <g filter="url(#filter)">
+ <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>`;
+
+ const img = new Image();
+ img.width = 90;
+ img.height = 90;
+ img.onload = () => {
+ ctx.translate(50, 40);
+ ctx.rotate(Math.PI);
+ ctx.translate(-45, -45);
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ // No globalAlpha.
+ // No globalCompositeOperation.
+ // No shadow.
+
+ ctx.drawImage(img, 0, 0);
+ };
+ img.src = 'data:image/svg+xml;base64,' + btoa(svg);
+ </script>
+</span>
+
+<span>
+ <div>globalAlpha</div>
+ <canvas id="canvas1" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas1");
+ const ctx = canvas.getContext('2d');
+
+ const svg = `
+ <svg xmlns="http://www.w3.org/2000/svg"
+ width="90" height="90"
+ color-interpolation-filters="sRGB">
+ <filter id="filter" x="-100%" y="-100%" width="300%" height="300%">
+ <feDropShadow dx="5" dy="5" stdDeviation="0" flood-color="#00f" />
+ <feComponentTransfer>
+ <feFuncA type="table" tableValues="0 0.8"></feFuncA>
+ </feComponentTransfer>
+ </filter>
+ <g filter="url(#filter)">
+ <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>`;
+
+ const img = new Image();
+ img.width = 90;
+ img.height = 90;
+ img.onload = () => {
+ ctx.translate(50, 40);
+ ctx.rotate(Math.PI);
+ ctx.translate(-45, -45);
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ ctx.globalAlpha = 0.75;
+ // No globalCompositeOperation.
+ // No shadow.
+
+ ctx.drawImage(img, 0, 0);
+ };
+ img.src = 'data:image/svg+xml;base64,' + btoa(svg);
+ </script>
+</span>
+
+</div>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.no-composite-op.no-shadow.rotation.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.no-composite-op.no-shadow.rotation.html
new file mode 100644
index 0000000000..5854af853c
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.no-composite-op.no-shadow.rotation.html
@@ -0,0 +1,89 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<link rel="match" href="2d.layer.global-states.filter.no-composite-op.no-shadow.rotation-expected.html">
+<title>Canvas test: 2d.layer.global-states.filter.no-composite-op.no-shadow.rotation</title>
+<h1 style="font-size: 20px;">2d.layer.global-states.filter.no-composite-op.no-shadow.rotation</h1>
+<p class="desc">Checks that layers with filters correctly use global render states.</p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(2, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>no-globalAlpha</div>
+ <canvas id="canvas0" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(90, 90);
+ const ctx = canvas.getContext('2d');
+
+ ctx.translate(50, 40);
+ ctx.rotate(Math.PI);
+ ctx.translate(-45, -45);
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ // No globalAlpha.
+ // No globalCompositeOperation.
+ // No shadow.
+
+ ctx.beginLayer({filter: [
+ {name: 'dropShadow',
+ dx: 5, dy: 5, stdDeviation: 0, floodColor: '#00f'},
+ {name: 'componentTransfer',
+ funcA: {type: "table", tableValues: [0, 0.8]}}]});
+
+ 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();
+
+ const outputCanvas = document.getElementById("canvas0");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>globalAlpha</div>
+ <canvas id="canvas1" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(90, 90);
+ const ctx = canvas.getContext('2d');
+
+ ctx.translate(50, 40);
+ ctx.rotate(Math.PI);
+ ctx.translate(-45, -45);
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ ctx.globalAlpha = 0.75;
+ // No globalCompositeOperation.
+ // No shadow.
+
+ ctx.beginLayer({filter: [
+ {name: 'dropShadow',
+ dx: 5, dy: 5, stdDeviation: 0, floodColor: '#00f'},
+ {name: 'componentTransfer',
+ funcA: {type: "table", tableValues: [0, 0.8]}}]});
+
+ 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();
+
+ const outputCanvas = document.getElementById("canvas1");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+</div>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.no-composite-op.no-shadow.rotation.w.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.no-composite-op.no-shadow.rotation.w.html
new file mode 100644
index 0000000000..c08f1f9f3c
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.no-composite-op.no-shadow.rotation.w.html
@@ -0,0 +1,120 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<html class="reftest-wait">
+<link rel="match" href="2d.layer.global-states.filter.no-composite-op.no-shadow.rotation-expected.html">
+<title>Canvas test: 2d.layer.global-states.filter.no-composite-op.no-shadow.rotation</title>
+<h1 style="font-size: 20px;">2d.layer.global-states.filter.no-composite-op.no-shadow.rotation</h1>
+<p class="desc">Checks that layers with filters correctly use global render states.</p>
+<script>pending_tests = 2;</script>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(2, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>no-globalAlpha</div>
+ <canvas id="canvas0" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script id="myWorker0" type="text/worker">
+ self.onmessage = function(e) {
+ const canvas = new OffscreenCanvas(90, 90);
+ const ctx = canvas.getContext('2d');
+
+ ctx.translate(50, 40);
+ ctx.rotate(Math.PI);
+ ctx.translate(-45, -45);
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ // No globalAlpha.
+ // No globalCompositeOperation.
+ // No shadow.
+
+ ctx.beginLayer({filter: [
+ {name: 'dropShadow',
+ dx: 5, dy: 5, stdDeviation: 0, floodColor: '#00f'},
+ {name: 'componentTransfer',
+ funcA: {type: "table", tableValues: [0, 0.8]}}]});
+
+ 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();
+
+ const bitmap = canvas.transferToImageBitmap();
+ self.postMessage(bitmap, bitmap);
+ };
+ </script>
+ <script type="module">
+ const blob = new Blob([document.getElementById('myWorker0').textContent]);
+ const worker = new Worker(URL.createObjectURL(blob));
+ worker.addEventListener('message', msg => {
+ const outputCanvas = document.getElementById('canvas0');
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(msg.data, 0, 0);
+ if (--pending_tests == 0) {
+ document.documentElement.classList.remove('reftest-wait');
+ }
+ });
+ worker.postMessage(null);
+ </script>
+</span>
+
+<span>
+ <div>globalAlpha</div>
+ <canvas id="canvas1" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script id="myWorker1" type="text/worker">
+ self.onmessage = function(e) {
+ const canvas = new OffscreenCanvas(90, 90);
+ const ctx = canvas.getContext('2d');
+
+ ctx.translate(50, 40);
+ ctx.rotate(Math.PI);
+ ctx.translate(-45, -45);
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ ctx.globalAlpha = 0.75;
+ // No globalCompositeOperation.
+ // No shadow.
+
+ ctx.beginLayer({filter: [
+ {name: 'dropShadow',
+ dx: 5, dy: 5, stdDeviation: 0, floodColor: '#00f'},
+ {name: 'componentTransfer',
+ funcA: {type: "table", tableValues: [0, 0.8]}}]});
+
+ 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();
+
+ const bitmap = canvas.transferToImageBitmap();
+ self.postMessage(bitmap, bitmap);
+ };
+ </script>
+ <script type="module">
+ const blob = new Blob([document.getElementById('myWorker1').textContent]);
+ const worker = new Worker(URL.createObjectURL(blob));
+ worker.addEventListener('message', msg => {
+ const outputCanvas = document.getElementById('canvas1');
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(msg.data, 0, 0);
+ if (--pending_tests == 0) {
+ document.documentElement.classList.remove('reftest-wait');
+ }
+ });
+ worker.postMessage(null);
+ </script>
+</span>
+
+</div>
+</html>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.no-composite-op.shadow.no-transform-expected.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.no-composite-op.shadow.no-transform-expected.html
new file mode 100644
index 0000000000..6bd4501584
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.no-composite-op.shadow.no-transform-expected.html
@@ -0,0 +1,104 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<title>Canvas test: 2d.layer.global-states.filter.no-composite-op.shadow.no-transform</title>
+<h1 style="font-size: 20px;">2d.layer.global-states.filter.no-composite-op.shadow.no-transform</h1>
+<p class="desc">Checks that layers with filters correctly use global render states.</p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(2, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>no-globalAlpha</div>
+ <canvas id="canvas0" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas0");
+ const ctx = canvas.getContext('2d');
+
+ const svg = `
+ <svg xmlns="http://www.w3.org/2000/svg"
+ width="90" height="90"
+ color-interpolation-filters="sRGB">
+ <filter id="filter" x="-100%" y="-100%" width="300%" height="300%">
+ <feDropShadow dx="5" dy="5" stdDeviation="0" flood-color="#00f" />
+ <feComponentTransfer>
+ <feFuncA type="table" tableValues="0 0.8"></feFuncA>
+ </feComponentTransfer>
+ </filter>
+ <g filter="url(#filter)">
+ <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>`;
+
+ const img = new Image();
+ img.width = 90;
+ img.height = 90;
+ img.onload = () => {
+ // No transform.
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ // No globalAlpha.
+ // No globalCompositeOperation.
+ ctx.shadowOffsetX = -7;
+ ctx.shadowOffsetY = 7;
+ ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
+ ctx.shadowBlur = 3;
+
+ ctx.drawImage(img, 0, 0);
+ };
+ img.src = 'data:image/svg+xml;base64,' + btoa(svg);
+ </script>
+</span>
+
+<span>
+ <div>globalAlpha</div>
+ <canvas id="canvas1" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas1");
+ const ctx = canvas.getContext('2d');
+
+ const svg = `
+ <svg xmlns="http://www.w3.org/2000/svg"
+ width="90" height="90"
+ color-interpolation-filters="sRGB">
+ <filter id="filter" x="-100%" y="-100%" width="300%" height="300%">
+ <feDropShadow dx="5" dy="5" stdDeviation="0" flood-color="#00f" />
+ <feComponentTransfer>
+ <feFuncA type="table" tableValues="0 0.8"></feFuncA>
+ </feComponentTransfer>
+ </filter>
+ <g filter="url(#filter)">
+ <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>`;
+
+ const img = new Image();
+ img.width = 90;
+ img.height = 90;
+ img.onload = () => {
+ // No transform.
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ ctx.globalAlpha = 0.75;
+ // No globalCompositeOperation.
+ ctx.shadowOffsetX = -7;
+ ctx.shadowOffsetY = 7;
+ ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
+ ctx.shadowBlur = 3;
+
+ ctx.drawImage(img, 0, 0);
+ };
+ img.src = 'data:image/svg+xml;base64,' + btoa(svg);
+ </script>
+</span>
+
+</div>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.no-composite-op.shadow.no-transform.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.no-composite-op.shadow.no-transform.html
new file mode 100644
index 0000000000..f1dc725b83
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.no-composite-op.shadow.no-transform.html
@@ -0,0 +1,91 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<link rel="match" href="2d.layer.global-states.filter.no-composite-op.shadow.no-transform-expected.html">
+<title>Canvas test: 2d.layer.global-states.filter.no-composite-op.shadow.no-transform</title>
+<h1 style="font-size: 20px;">2d.layer.global-states.filter.no-composite-op.shadow.no-transform</h1>
+<p class="desc">Checks that layers with filters correctly use global render states.</p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(2, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>no-globalAlpha</div>
+ <canvas id="canvas0" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(90, 90);
+ const ctx = canvas.getContext('2d');
+
+ // No transform.
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ // No globalAlpha.
+ // No globalCompositeOperation.
+ ctx.shadowOffsetX = -7;
+ ctx.shadowOffsetY = 7;
+ ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
+ ctx.shadowBlur = 3;
+
+ ctx.beginLayer({filter: [
+ {name: 'dropShadow',
+ dx: 5, dy: 5, stdDeviation: 0, floodColor: '#00f'},
+ {name: 'componentTransfer',
+ funcA: {type: "table", tableValues: [0, 0.8]}}]});
+
+ 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();
+
+ const outputCanvas = document.getElementById("canvas0");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>globalAlpha</div>
+ <canvas id="canvas1" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(90, 90);
+ const ctx = canvas.getContext('2d');
+
+ // No transform.
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ ctx.globalAlpha = 0.75;
+ // No globalCompositeOperation.
+ ctx.shadowOffsetX = -7;
+ ctx.shadowOffsetY = 7;
+ ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
+ ctx.shadowBlur = 3;
+
+ ctx.beginLayer({filter: [
+ {name: 'dropShadow',
+ dx: 5, dy: 5, stdDeviation: 0, floodColor: '#00f'},
+ {name: 'componentTransfer',
+ funcA: {type: "table", tableValues: [0, 0.8]}}]});
+
+ 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();
+
+ const outputCanvas = document.getElementById("canvas1");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+</div>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.no-composite-op.shadow.no-transform.w.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.no-composite-op.shadow.no-transform.w.html
new file mode 100644
index 0000000000..f191747805
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.no-composite-op.shadow.no-transform.w.html
@@ -0,0 +1,122 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<html class="reftest-wait">
+<link rel="match" href="2d.layer.global-states.filter.no-composite-op.shadow.no-transform-expected.html">
+<title>Canvas test: 2d.layer.global-states.filter.no-composite-op.shadow.no-transform</title>
+<h1 style="font-size: 20px;">2d.layer.global-states.filter.no-composite-op.shadow.no-transform</h1>
+<p class="desc">Checks that layers with filters correctly use global render states.</p>
+<script>pending_tests = 2;</script>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(2, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>no-globalAlpha</div>
+ <canvas id="canvas0" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script id="myWorker0" type="text/worker">
+ self.onmessage = function(e) {
+ const canvas = new OffscreenCanvas(90, 90);
+ const ctx = canvas.getContext('2d');
+
+ // No transform.
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ // No globalAlpha.
+ // No globalCompositeOperation.
+ ctx.shadowOffsetX = -7;
+ ctx.shadowOffsetY = 7;
+ ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
+ ctx.shadowBlur = 3;
+
+ ctx.beginLayer({filter: [
+ {name: 'dropShadow',
+ dx: 5, dy: 5, stdDeviation: 0, floodColor: '#00f'},
+ {name: 'componentTransfer',
+ funcA: {type: "table", tableValues: [0, 0.8]}}]});
+
+ 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();
+
+ const bitmap = canvas.transferToImageBitmap();
+ self.postMessage(bitmap, bitmap);
+ };
+ </script>
+ <script type="module">
+ const blob = new Blob([document.getElementById('myWorker0').textContent]);
+ const worker = new Worker(URL.createObjectURL(blob));
+ worker.addEventListener('message', msg => {
+ const outputCanvas = document.getElementById('canvas0');
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(msg.data, 0, 0);
+ if (--pending_tests == 0) {
+ document.documentElement.classList.remove('reftest-wait');
+ }
+ });
+ worker.postMessage(null);
+ </script>
+</span>
+
+<span>
+ <div>globalAlpha</div>
+ <canvas id="canvas1" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script id="myWorker1" type="text/worker">
+ self.onmessage = function(e) {
+ const canvas = new OffscreenCanvas(90, 90);
+ const ctx = canvas.getContext('2d');
+
+ // No transform.
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ ctx.globalAlpha = 0.75;
+ // No globalCompositeOperation.
+ ctx.shadowOffsetX = -7;
+ ctx.shadowOffsetY = 7;
+ ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
+ ctx.shadowBlur = 3;
+
+ ctx.beginLayer({filter: [
+ {name: 'dropShadow',
+ dx: 5, dy: 5, stdDeviation: 0, floodColor: '#00f'},
+ {name: 'componentTransfer',
+ funcA: {type: "table", tableValues: [0, 0.8]}}]});
+
+ 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();
+
+ const bitmap = canvas.transferToImageBitmap();
+ self.postMessage(bitmap, bitmap);
+ };
+ </script>
+ <script type="module">
+ const blob = new Blob([document.getElementById('myWorker1').textContent]);
+ const worker = new Worker(URL.createObjectURL(blob));
+ worker.addEventListener('message', msg => {
+ const outputCanvas = document.getElementById('canvas1');
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(msg.data, 0, 0);
+ if (--pending_tests == 0) {
+ document.documentElement.classList.remove('reftest-wait');
+ }
+ });
+ worker.postMessage(null);
+ </script>
+</span>
+
+</div>
+</html>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.no-composite-op.shadow.rotation-expected.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.no-composite-op.shadow.rotation-expected.html
new file mode 100644
index 0000000000..b60a5526d9
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.no-composite-op.shadow.rotation-expected.html
@@ -0,0 +1,108 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<title>Canvas test: 2d.layer.global-states.filter.no-composite-op.shadow.rotation</title>
+<h1 style="font-size: 20px;">2d.layer.global-states.filter.no-composite-op.shadow.rotation</h1>
+<p class="desc">Checks that layers with filters correctly use global render states.</p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(2, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>no-globalAlpha</div>
+ <canvas id="canvas0" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas0");
+ const ctx = canvas.getContext('2d');
+
+ const svg = `
+ <svg xmlns="http://www.w3.org/2000/svg"
+ width="90" height="90"
+ color-interpolation-filters="sRGB">
+ <filter id="filter" x="-100%" y="-100%" width="300%" height="300%">
+ <feDropShadow dx="5" dy="5" stdDeviation="0" flood-color="#00f" />
+ <feComponentTransfer>
+ <feFuncA type="table" tableValues="0 0.8"></feFuncA>
+ </feComponentTransfer>
+ </filter>
+ <g filter="url(#filter)">
+ <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>`;
+
+ const img = new Image();
+ img.width = 90;
+ img.height = 90;
+ img.onload = () => {
+ ctx.translate(50, 40);
+ ctx.rotate(Math.PI);
+ ctx.translate(-45, -45);
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ // No globalAlpha.
+ // No globalCompositeOperation.
+ ctx.shadowOffsetX = -7;
+ ctx.shadowOffsetY = 7;
+ ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
+ ctx.shadowBlur = 3;
+
+ ctx.drawImage(img, 0, 0);
+ };
+ img.src = 'data:image/svg+xml;base64,' + btoa(svg);
+ </script>
+</span>
+
+<span>
+ <div>globalAlpha</div>
+ <canvas id="canvas1" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas1");
+ const ctx = canvas.getContext('2d');
+
+ const svg = `
+ <svg xmlns="http://www.w3.org/2000/svg"
+ width="90" height="90"
+ color-interpolation-filters="sRGB">
+ <filter id="filter" x="-100%" y="-100%" width="300%" height="300%">
+ <feDropShadow dx="5" dy="5" stdDeviation="0" flood-color="#00f" />
+ <feComponentTransfer>
+ <feFuncA type="table" tableValues="0 0.8"></feFuncA>
+ </feComponentTransfer>
+ </filter>
+ <g filter="url(#filter)">
+ <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>`;
+
+ const img = new Image();
+ img.width = 90;
+ img.height = 90;
+ img.onload = () => {
+ ctx.translate(50, 40);
+ ctx.rotate(Math.PI);
+ ctx.translate(-45, -45);
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ ctx.globalAlpha = 0.75;
+ // No globalCompositeOperation.
+ ctx.shadowOffsetX = -7;
+ ctx.shadowOffsetY = 7;
+ ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
+ ctx.shadowBlur = 3;
+
+ ctx.drawImage(img, 0, 0);
+ };
+ img.src = 'data:image/svg+xml;base64,' + btoa(svg);
+ </script>
+</span>
+
+</div>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.no-composite-op.shadow.rotation.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.no-composite-op.shadow.rotation.html
new file mode 100644
index 0000000000..76258b326d
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.no-composite-op.shadow.rotation.html
@@ -0,0 +1,95 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<link rel="match" href="2d.layer.global-states.filter.no-composite-op.shadow.rotation-expected.html">
+<title>Canvas test: 2d.layer.global-states.filter.no-composite-op.shadow.rotation</title>
+<h1 style="font-size: 20px;">2d.layer.global-states.filter.no-composite-op.shadow.rotation</h1>
+<p class="desc">Checks that layers with filters correctly use global render states.</p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(2, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>no-globalAlpha</div>
+ <canvas id="canvas0" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(90, 90);
+ const ctx = canvas.getContext('2d');
+
+ ctx.translate(50, 40);
+ ctx.rotate(Math.PI);
+ ctx.translate(-45, -45);
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ // No globalAlpha.
+ // No globalCompositeOperation.
+ ctx.shadowOffsetX = -7;
+ ctx.shadowOffsetY = 7;
+ ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
+ ctx.shadowBlur = 3;
+
+ ctx.beginLayer({filter: [
+ {name: 'dropShadow',
+ dx: 5, dy: 5, stdDeviation: 0, floodColor: '#00f'},
+ {name: 'componentTransfer',
+ funcA: {type: "table", tableValues: [0, 0.8]}}]});
+
+ 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();
+
+ const outputCanvas = document.getElementById("canvas0");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>globalAlpha</div>
+ <canvas id="canvas1" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(90, 90);
+ const ctx = canvas.getContext('2d');
+
+ ctx.translate(50, 40);
+ ctx.rotate(Math.PI);
+ ctx.translate(-45, -45);
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ ctx.globalAlpha = 0.75;
+ // No globalCompositeOperation.
+ ctx.shadowOffsetX = -7;
+ ctx.shadowOffsetY = 7;
+ ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
+ ctx.shadowBlur = 3;
+
+ ctx.beginLayer({filter: [
+ {name: 'dropShadow',
+ dx: 5, dy: 5, stdDeviation: 0, floodColor: '#00f'},
+ {name: 'componentTransfer',
+ funcA: {type: "table", tableValues: [0, 0.8]}}]});
+
+ 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();
+
+ const outputCanvas = document.getElementById("canvas1");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+</div>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.no-composite-op.shadow.rotation.w.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.no-composite-op.shadow.rotation.w.html
new file mode 100644
index 0000000000..9a10fb569f
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.no-composite-op.shadow.rotation.w.html
@@ -0,0 +1,126 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<html class="reftest-wait">
+<link rel="match" href="2d.layer.global-states.filter.no-composite-op.shadow.rotation-expected.html">
+<title>Canvas test: 2d.layer.global-states.filter.no-composite-op.shadow.rotation</title>
+<h1 style="font-size: 20px;">2d.layer.global-states.filter.no-composite-op.shadow.rotation</h1>
+<p class="desc">Checks that layers with filters correctly use global render states.</p>
+<script>pending_tests = 2;</script>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(2, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>no-globalAlpha</div>
+ <canvas id="canvas0" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script id="myWorker0" type="text/worker">
+ self.onmessage = function(e) {
+ const canvas = new OffscreenCanvas(90, 90);
+ const ctx = canvas.getContext('2d');
+
+ ctx.translate(50, 40);
+ ctx.rotate(Math.PI);
+ ctx.translate(-45, -45);
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ // No globalAlpha.
+ // No globalCompositeOperation.
+ ctx.shadowOffsetX = -7;
+ ctx.shadowOffsetY = 7;
+ ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
+ ctx.shadowBlur = 3;
+
+ ctx.beginLayer({filter: [
+ {name: 'dropShadow',
+ dx: 5, dy: 5, stdDeviation: 0, floodColor: '#00f'},
+ {name: 'componentTransfer',
+ funcA: {type: "table", tableValues: [0, 0.8]}}]});
+
+ 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();
+
+ const bitmap = canvas.transferToImageBitmap();
+ self.postMessage(bitmap, bitmap);
+ };
+ </script>
+ <script type="module">
+ const blob = new Blob([document.getElementById('myWorker0').textContent]);
+ const worker = new Worker(URL.createObjectURL(blob));
+ worker.addEventListener('message', msg => {
+ const outputCanvas = document.getElementById('canvas0');
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(msg.data, 0, 0);
+ if (--pending_tests == 0) {
+ document.documentElement.classList.remove('reftest-wait');
+ }
+ });
+ worker.postMessage(null);
+ </script>
+</span>
+
+<span>
+ <div>globalAlpha</div>
+ <canvas id="canvas1" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script id="myWorker1" type="text/worker">
+ self.onmessage = function(e) {
+ const canvas = new OffscreenCanvas(90, 90);
+ const ctx = canvas.getContext('2d');
+
+ ctx.translate(50, 40);
+ ctx.rotate(Math.PI);
+ ctx.translate(-45, -45);
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ ctx.globalAlpha = 0.75;
+ // No globalCompositeOperation.
+ ctx.shadowOffsetX = -7;
+ ctx.shadowOffsetY = 7;
+ ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
+ ctx.shadowBlur = 3;
+
+ ctx.beginLayer({filter: [
+ {name: 'dropShadow',
+ dx: 5, dy: 5, stdDeviation: 0, floodColor: '#00f'},
+ {name: 'componentTransfer',
+ funcA: {type: "table", tableValues: [0, 0.8]}}]});
+
+ 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();
+
+ const bitmap = canvas.transferToImageBitmap();
+ self.postMessage(bitmap, bitmap);
+ };
+ </script>
+ <script type="module">
+ const blob = new Blob([document.getElementById('myWorker1').textContent]);
+ const worker = new Worker(URL.createObjectURL(blob));
+ worker.addEventListener('message', msg => {
+ const outputCanvas = document.getElementById('canvas1');
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(msg.data, 0, 0);
+ if (--pending_tests == 0) {
+ document.documentElement.classList.remove('reftest-wait');
+ }
+ });
+ worker.postMessage(null);
+ </script>
+</span>
+
+</div>
+</html>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.no-global-states-expected.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.no-global-states-expected.html
deleted file mode 100644
index e56fe0b360..0000000000
--- a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.no-global-states-expected.html
+++ /dev/null
@@ -1,50 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<title>Canvas test: 2d.layer.global-states.filter.no-global-states</title>
-<h1>2d.layer.global-states.filter.no-global-states</h1>
-<p class="desc">Checks that layers with filters correctly use global render states.</p>
-<canvas id="canvas" width="200" height="200">
- <p class="fallback">FAIL (fallback content)</p>
-</canvas>
-<script>
- const canvas = document.getElementById("canvas");
- const ctx = canvas.getContext('2d');
-
- const svg = `
- <svg xmlns="http://www.w3.org/2000/svg"
- width="200" height="200"
- 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" />
- <feComponentTransfer>
- <feFuncA type="table" tableValues="0 0.7"></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)"/>
- </g>
- </svg>`;
-
- const img = new Image();
- img.width = 200;
- img.height = 200;
- img.onload = () => {
- ctx.fillStyle = 'rgba(0, 0, 255, 1)';
-
- var circle = new Path2D();
- circle.arc(90, 90, 45, 0, 2 * Math.PI);
- ctx.fill(circle);
-
- // No global states.
-
- ctx.drawImage(img, 0, 0);
- };
- img.src = 'data:image/svg+xml;base64,' + btoa(svg);
-</script>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.no-global-states.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.no-global-states.html
deleted file mode 100644
index 3effa3ee9d..0000000000
--- a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.no-global-states.html
+++ /dev/null
@@ -1,40 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<link rel="match" href="2d.layer.global-states.filter.no-global-states-expected.html">
-<title>Canvas test: 2d.layer.global-states.filter.no-global-states</title>
-<h1>2d.layer.global-states.filter.no-global-states</h1>
-<p class="desc">Checks that layers with filters correctly use global render states.</p>
-<canvas id="canvas" width="200" height="200">
- <p class="fallback">FAIL (fallback content)</p>
-</canvas>
-<script>
- const canvas = new OffscreenCanvas(200, 200);
- const ctx = canvas.getContext('2d');
-
- ctx.fillStyle = 'rgba(0, 0, 255, 1)';
-
- var circle = new Path2D();
- circle.arc(90, 90, 45, 0, 2 * Math.PI);
- ctx.fill(circle);
-
- // No global states.
-
- 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: 'componentTransfer',
- funcA: {type: "table", tableValues: [0, 0.7]}},
- {name: 'dropShadow', dx: 5, dy: 5, floodColor: '#81e'}]});
-
- 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.endLayer();
-
- const outputCanvas = document.getElementById("canvas");
- outputCanvas.getContext('2d').drawImage(canvas, 0, 0);
-</script>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.no-global-states.w.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.no-global-states.w.html
deleted file mode 100644
index ec744d7ffe..0000000000
--- a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.no-global-states.w.html
+++ /dev/null
@@ -1,54 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<html class="reftest-wait">
-<link rel="match" href="2d.layer.global-states.filter.no-global-states-expected.html">
-<title>Canvas test: 2d.layer.global-states.filter.no-global-states</title>
-<h1>2d.layer.global-states.filter.no-global-states</h1>
-<p class="desc">Checks that layers with filters correctly use global render states.</p>
-<canvas id="canvas" width="200" height="200">
- <p class="fallback">FAIL (fallback content)</p>
-</canvas>
-<script id='myWorker' type='text/worker'>
- self.onmessage = function(e) {
- const canvas = new OffscreenCanvas(200, 200);
- const ctx = canvas.getContext('2d');
-
- ctx.fillStyle = 'rgba(0, 0, 255, 1)';
-
- var circle = new Path2D();
- circle.arc(90, 90, 45, 0, 2 * Math.PI);
- ctx.fill(circle);
-
- // No global states.
-
- 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: 'componentTransfer',
- funcA: {type: "table", tableValues: [0, 0.7]}},
- {name: 'dropShadow', dx: 5, dy: 5, floodColor: '#81e'}]});
-
- 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.endLayer();
-
- const bitmap = canvas.transferToImageBitmap();
- self.postMessage(bitmap, bitmap);
- };
-</script>
-<script>
- const blob = new Blob([document.getElementById('myWorker').textContent]);
- const worker = new Worker(URL.createObjectURL(blob));
- worker.addEventListener('message', msg => {
- const outputCtx = document.getElementById("canvas").getContext('2d');
- outputCtx.drawImage(msg.data, 0, 0);
- document.documentElement.classList.remove("reftest-wait");
- });
- worker.postMessage(null);
-</script>
-</html>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.shadow-expected.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.shadow-expected.html
deleted file mode 100644
index 13ba2dd4cd..0000000000
--- a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.shadow-expected.html
+++ /dev/null
@@ -1,53 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<title>Canvas test: 2d.layer.global-states.filter.shadow</title>
-<h1>2d.layer.global-states.filter.shadow</h1>
-<p class="desc">Checks that layers with filters correctly use global render states.</p>
-<canvas id="canvas" width="200" height="200">
- <p class="fallback">FAIL (fallback content)</p>
-</canvas>
-<script>
- const canvas = document.getElementById("canvas");
- const ctx = canvas.getContext('2d');
-
- const svg = `
- <svg xmlns="http://www.w3.org/2000/svg"
- width="200" height="200"
- 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" />
- <feComponentTransfer>
- <feFuncA type="table" tableValues="0 0.7"></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)"/>
- </g>
- </svg>`;
-
- const img = new Image();
- img.width = 200;
- img.height = 200;
- img.onload = () => {
- ctx.fillStyle = 'rgba(0, 0, 255, 1)';
-
- var circle = new Path2D();
- circle.arc(90, 90, 45, 0, 2 * Math.PI);
- ctx.fill(circle);
-
- ctx.shadowOffsetX = -10;
- ctx.shadowOffsetY = 10;
- ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
- ctx.shadowBlur = 3;
-
- ctx.drawImage(img, 0, 0);
- };
- img.src = 'data:image/svg+xml;base64,' + btoa(svg);
-</script>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.shadow.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.shadow.html
deleted file mode 100644
index 7bb0ef5e13..0000000000
--- a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.shadow.html
+++ /dev/null
@@ -1,43 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<link rel="match" href="2d.layer.global-states.filter.shadow-expected.html">
-<title>Canvas test: 2d.layer.global-states.filter.shadow</title>
-<h1>2d.layer.global-states.filter.shadow</h1>
-<p class="desc">Checks that layers with filters correctly use global render states.</p>
-<canvas id="canvas" width="200" height="200">
- <p class="fallback">FAIL (fallback content)</p>
-</canvas>
-<script>
- const canvas = new OffscreenCanvas(200, 200);
- const ctx = canvas.getContext('2d');
-
- ctx.fillStyle = 'rgba(0, 0, 255, 1)';
-
- var circle = new Path2D();
- circle.arc(90, 90, 45, 0, 2 * Math.PI);
- ctx.fill(circle);
-
- ctx.shadowOffsetX = -10;
- ctx.shadowOffsetY = 10;
- ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
- ctx.shadowBlur = 3;
-
- 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: 'componentTransfer',
- funcA: {type: "table", tableValues: [0, 0.7]}},
- {name: 'dropShadow', dx: 5, dy: 5, floodColor: '#81e'}]});
-
- 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.endLayer();
-
- const outputCanvas = document.getElementById("canvas");
- outputCanvas.getContext('2d').drawImage(canvas, 0, 0);
-</script>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.shadow.w.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.shadow.w.html
deleted file mode 100644
index bc9bd48aad..0000000000
--- a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.filter.shadow.w.html
+++ /dev/null
@@ -1,57 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<html class="reftest-wait">
-<link rel="match" href="2d.layer.global-states.filter.shadow-expected.html">
-<title>Canvas test: 2d.layer.global-states.filter.shadow</title>
-<h1>2d.layer.global-states.filter.shadow</h1>
-<p class="desc">Checks that layers with filters correctly use global render states.</p>
-<canvas id="canvas" width="200" height="200">
- <p class="fallback">FAIL (fallback content)</p>
-</canvas>
-<script id='myWorker' type='text/worker'>
- self.onmessage = function(e) {
- const canvas = new OffscreenCanvas(200, 200);
- const ctx = canvas.getContext('2d');
-
- ctx.fillStyle = 'rgba(0, 0, 255, 1)';
-
- var circle = new Path2D();
- circle.arc(90, 90, 45, 0, 2 * Math.PI);
- ctx.fill(circle);
-
- ctx.shadowOffsetX = -10;
- ctx.shadowOffsetY = 10;
- ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
- ctx.shadowBlur = 3;
-
- 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: 'componentTransfer',
- funcA: {type: "table", tableValues: [0, 0.7]}},
- {name: 'dropShadow', dx: 5, dy: 5, floodColor: '#81e'}]});
-
- 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.endLayer();
-
- const bitmap = canvas.transferToImageBitmap();
- self.postMessage(bitmap, bitmap);
- };
-</script>
-<script>
- const blob = new Blob([document.getElementById('myWorker').textContent]);
- const worker = new Worker(URL.createObjectURL(blob));
- worker.addEventListener('message', msg => {
- const outputCtx = document.getElementById("canvas").getContext('2d');
- outputCtx.drawImage(msg.data, 0, 0);
- document.documentElement.classList.remove("reftest-wait");
- });
- worker.postMessage(null);
-</script>
-</html>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.no-composite-op.no-shadow.no-transform-expected.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.no-composite-op.no-shadow.no-transform-expected.html
new file mode 100644
index 0000000000..d1a799707f
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.no-composite-op.no-shadow.no-transform-expected.html
@@ -0,0 +1,72 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<title>Canvas test: 2d.layer.global-states.no-composite-op.no-shadow.no-transform</title>
+<h1 style="font-size: 20px;">2d.layer.global-states.no-composite-op.no-shadow.no-transform</h1>
+<p class="desc">Checks that layers correctly use global render states.</p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(2, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>no-globalAlpha</div>
+ <canvas id="canvas0" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas0");
+ const ctx = canvas.getContext('2d');
+
+ // No transform.
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ // No globalAlpha.
+ // No globalCompositeOperation.
+ // No shadow.
+
+ const canvas2 = document.createElement("canvas");
+ const ctx2 = canvas2.getContext("2d");
+
+ ctx2.globalCompositeOperation = 'screen';
+ ctx2.fillStyle = 'rgba(255, 0, 0, 1)';
+ ctx2.fillRect(10, 25, 40, 50);
+ ctx2.fillStyle = 'rgba(0, 255, 0, 1)';
+ ctx2.fillRect(30, 5, 50, 40);
+
+ ctx.drawImage(canvas2, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>globalAlpha</div>
+ <canvas id="canvas1" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas1");
+ const ctx = canvas.getContext('2d');
+
+ // No transform.
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ ctx.globalAlpha = 0.75;
+ // No globalCompositeOperation.
+ // No shadow.
+
+ const canvas2 = document.createElement("canvas");
+ const ctx2 = canvas2.getContext("2d");
+
+ ctx2.globalCompositeOperation = 'screen';
+ ctx2.fillStyle = 'rgba(255, 0, 0, 1)';
+ ctx2.fillRect(10, 25, 40, 50);
+ ctx2.fillStyle = 'rgba(0, 255, 0, 1)';
+ ctx2.fillRect(30, 5, 50, 40);
+
+ ctx.drawImage(canvas2, 0, 0);
+ </script>
+</span>
+
+</div>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.no-composite-op.no-shadow.no-transform.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.no-composite-op.no-shadow.no-transform.html
new file mode 100644
index 0000000000..016f78a5d8
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.no-composite-op.no-shadow.no-transform.html
@@ -0,0 +1,85 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<link rel="match" href="2d.layer.global-states.no-composite-op.no-shadow.no-transform-expected.html">
+<title>Canvas test: 2d.layer.global-states.no-composite-op.no-shadow.no-transform</title>
+<h1 style="font-size: 20px;">2d.layer.global-states.no-composite-op.no-shadow.no-transform</h1>
+<p class="desc">Checks that layers correctly use global render states.</p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(2, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>no-globalAlpha</div>
+ <canvas id="canvas0" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(90, 90);
+ const ctx = canvas.getContext('2d');
+
+ // No transform.
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ // No globalAlpha.
+ // No globalCompositeOperation.
+ // No shadow.
+
+ ctx.beginLayer();
+
+ // Enable compositing in the layer to validate that draw calls in the layer
+ // won't individually composite with the background.
+ ctx.globalCompositeOperation = 'screen';
+
+ 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();
+
+ const outputCanvas = document.getElementById("canvas0");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>globalAlpha</div>
+ <canvas id="canvas1" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(90, 90);
+ const ctx = canvas.getContext('2d');
+
+ // No transform.
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ ctx.globalAlpha = 0.75;
+ // No globalCompositeOperation.
+ // No shadow.
+
+ ctx.beginLayer();
+
+ // Enable compositing in the layer to validate that draw calls in the layer
+ // won't individually composite with the background.
+ ctx.globalCompositeOperation = 'screen';
+
+ 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();
+
+ const outputCanvas = document.getElementById("canvas1");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+</div>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.no-composite-op.no-shadow.no-transform.w.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.no-composite-op.no-shadow.no-transform.w.html
new file mode 100644
index 0000000000..2a450624f1
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.no-composite-op.no-shadow.no-transform.w.html
@@ -0,0 +1,116 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<html class="reftest-wait">
+<link rel="match" href="2d.layer.global-states.no-composite-op.no-shadow.no-transform-expected.html">
+<title>Canvas test: 2d.layer.global-states.no-composite-op.no-shadow.no-transform</title>
+<h1 style="font-size: 20px;">2d.layer.global-states.no-composite-op.no-shadow.no-transform</h1>
+<p class="desc">Checks that layers correctly use global render states.</p>
+<script>pending_tests = 2;</script>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(2, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>no-globalAlpha</div>
+ <canvas id="canvas0" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script id="myWorker0" type="text/worker">
+ self.onmessage = function(e) {
+ const canvas = new OffscreenCanvas(90, 90);
+ const ctx = canvas.getContext('2d');
+
+ // No transform.
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ // No globalAlpha.
+ // No globalCompositeOperation.
+ // No shadow.
+
+ ctx.beginLayer();
+
+ // Enable compositing in the layer to validate that draw calls in the layer
+ // won't individually composite with the background.
+ ctx.globalCompositeOperation = 'screen';
+
+ 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();
+
+ const bitmap = canvas.transferToImageBitmap();
+ self.postMessage(bitmap, bitmap);
+ };
+ </script>
+ <script type="module">
+ const blob = new Blob([document.getElementById('myWorker0').textContent]);
+ const worker = new Worker(URL.createObjectURL(blob));
+ worker.addEventListener('message', msg => {
+ const outputCanvas = document.getElementById('canvas0');
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(msg.data, 0, 0);
+ if (--pending_tests == 0) {
+ document.documentElement.classList.remove('reftest-wait');
+ }
+ });
+ worker.postMessage(null);
+ </script>
+</span>
+
+<span>
+ <div>globalAlpha</div>
+ <canvas id="canvas1" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script id="myWorker1" type="text/worker">
+ self.onmessage = function(e) {
+ const canvas = new OffscreenCanvas(90, 90);
+ const ctx = canvas.getContext('2d');
+
+ // No transform.
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ ctx.globalAlpha = 0.75;
+ // No globalCompositeOperation.
+ // No shadow.
+
+ ctx.beginLayer();
+
+ // Enable compositing in the layer to validate that draw calls in the layer
+ // won't individually composite with the background.
+ ctx.globalCompositeOperation = 'screen';
+
+ 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();
+
+ const bitmap = canvas.transferToImageBitmap();
+ self.postMessage(bitmap, bitmap);
+ };
+ </script>
+ <script type="module">
+ const blob = new Blob([document.getElementById('myWorker1').textContent]);
+ const worker = new Worker(URL.createObjectURL(blob));
+ worker.addEventListener('message', msg => {
+ const outputCanvas = document.getElementById('canvas1');
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(msg.data, 0, 0);
+ if (--pending_tests == 0) {
+ document.documentElement.classList.remove('reftest-wait');
+ }
+ });
+ worker.postMessage(null);
+ </script>
+</span>
+
+</div>
+</html>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.no-composite-op.no-shadow.rotation-expected.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.no-composite-op.no-shadow.rotation-expected.html
new file mode 100644
index 0000000000..cc91a67faf
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.no-composite-op.no-shadow.rotation-expected.html
@@ -0,0 +1,76 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<title>Canvas test: 2d.layer.global-states.no-composite-op.no-shadow.rotation</title>
+<h1 style="font-size: 20px;">2d.layer.global-states.no-composite-op.no-shadow.rotation</h1>
+<p class="desc">Checks that layers correctly use global render states.</p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(2, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>no-globalAlpha</div>
+ <canvas id="canvas0" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas0");
+ const ctx = canvas.getContext('2d');
+
+ ctx.translate(50, 40);
+ ctx.rotate(Math.PI);
+ ctx.translate(-45, -45);
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ // No globalAlpha.
+ // No globalCompositeOperation.
+ // No shadow.
+
+ const canvas2 = document.createElement("canvas");
+ const ctx2 = canvas2.getContext("2d");
+
+ ctx2.globalCompositeOperation = 'screen';
+ ctx2.fillStyle = 'rgba(255, 0, 0, 1)';
+ ctx2.fillRect(10, 25, 40, 50);
+ ctx2.fillStyle = 'rgba(0, 255, 0, 1)';
+ ctx2.fillRect(30, 5, 50, 40);
+
+ ctx.drawImage(canvas2, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>globalAlpha</div>
+ <canvas id="canvas1" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas1");
+ const ctx = canvas.getContext('2d');
+
+ ctx.translate(50, 40);
+ ctx.rotate(Math.PI);
+ ctx.translate(-45, -45);
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ ctx.globalAlpha = 0.75;
+ // No globalCompositeOperation.
+ // No shadow.
+
+ const canvas2 = document.createElement("canvas");
+ const ctx2 = canvas2.getContext("2d");
+
+ ctx2.globalCompositeOperation = 'screen';
+ ctx2.fillStyle = 'rgba(255, 0, 0, 1)';
+ ctx2.fillRect(10, 25, 40, 50);
+ ctx2.fillStyle = 'rgba(0, 255, 0, 1)';
+ ctx2.fillRect(30, 5, 50, 40);
+
+ ctx.drawImage(canvas2, 0, 0);
+ </script>
+</span>
+
+</div>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.no-composite-op.no-shadow.rotation.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.no-composite-op.no-shadow.rotation.html
new file mode 100644
index 0000000000..12a1e64b42
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.no-composite-op.no-shadow.rotation.html
@@ -0,0 +1,89 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<link rel="match" href="2d.layer.global-states.no-composite-op.no-shadow.rotation-expected.html">
+<title>Canvas test: 2d.layer.global-states.no-composite-op.no-shadow.rotation</title>
+<h1 style="font-size: 20px;">2d.layer.global-states.no-composite-op.no-shadow.rotation</h1>
+<p class="desc">Checks that layers correctly use global render states.</p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(2, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>no-globalAlpha</div>
+ <canvas id="canvas0" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(90, 90);
+ const ctx = canvas.getContext('2d');
+
+ ctx.translate(50, 40);
+ ctx.rotate(Math.PI);
+ ctx.translate(-45, -45);
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ // No globalAlpha.
+ // No globalCompositeOperation.
+ // No shadow.
+
+ ctx.beginLayer();
+
+ // Enable compositing in the layer to validate that draw calls in the layer
+ // won't individually composite with the background.
+ ctx.globalCompositeOperation = 'screen';
+
+ 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();
+
+ const outputCanvas = document.getElementById("canvas0");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>globalAlpha</div>
+ <canvas id="canvas1" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(90, 90);
+ const ctx = canvas.getContext('2d');
+
+ ctx.translate(50, 40);
+ ctx.rotate(Math.PI);
+ ctx.translate(-45, -45);
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ ctx.globalAlpha = 0.75;
+ // No globalCompositeOperation.
+ // No shadow.
+
+ ctx.beginLayer();
+
+ // Enable compositing in the layer to validate that draw calls in the layer
+ // won't individually composite with the background.
+ ctx.globalCompositeOperation = 'screen';
+
+ 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();
+
+ const outputCanvas = document.getElementById("canvas1");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+</div>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.no-composite-op.no-shadow.rotation.w.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.no-composite-op.no-shadow.rotation.w.html
new file mode 100644
index 0000000000..a0f5f76099
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.no-composite-op.no-shadow.rotation.w.html
@@ -0,0 +1,120 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<html class="reftest-wait">
+<link rel="match" href="2d.layer.global-states.no-composite-op.no-shadow.rotation-expected.html">
+<title>Canvas test: 2d.layer.global-states.no-composite-op.no-shadow.rotation</title>
+<h1 style="font-size: 20px;">2d.layer.global-states.no-composite-op.no-shadow.rotation</h1>
+<p class="desc">Checks that layers correctly use global render states.</p>
+<script>pending_tests = 2;</script>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(2, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>no-globalAlpha</div>
+ <canvas id="canvas0" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script id="myWorker0" type="text/worker">
+ self.onmessage = function(e) {
+ const canvas = new OffscreenCanvas(90, 90);
+ const ctx = canvas.getContext('2d');
+
+ ctx.translate(50, 40);
+ ctx.rotate(Math.PI);
+ ctx.translate(-45, -45);
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ // No globalAlpha.
+ // No globalCompositeOperation.
+ // No shadow.
+
+ ctx.beginLayer();
+
+ // Enable compositing in the layer to validate that draw calls in the layer
+ // won't individually composite with the background.
+ ctx.globalCompositeOperation = 'screen';
+
+ 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();
+
+ const bitmap = canvas.transferToImageBitmap();
+ self.postMessage(bitmap, bitmap);
+ };
+ </script>
+ <script type="module">
+ const blob = new Blob([document.getElementById('myWorker0').textContent]);
+ const worker = new Worker(URL.createObjectURL(blob));
+ worker.addEventListener('message', msg => {
+ const outputCanvas = document.getElementById('canvas0');
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(msg.data, 0, 0);
+ if (--pending_tests == 0) {
+ document.documentElement.classList.remove('reftest-wait');
+ }
+ });
+ worker.postMessage(null);
+ </script>
+</span>
+
+<span>
+ <div>globalAlpha</div>
+ <canvas id="canvas1" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script id="myWorker1" type="text/worker">
+ self.onmessage = function(e) {
+ const canvas = new OffscreenCanvas(90, 90);
+ const ctx = canvas.getContext('2d');
+
+ ctx.translate(50, 40);
+ ctx.rotate(Math.PI);
+ ctx.translate(-45, -45);
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ ctx.globalAlpha = 0.75;
+ // No globalCompositeOperation.
+ // No shadow.
+
+ ctx.beginLayer();
+
+ // Enable compositing in the layer to validate that draw calls in the layer
+ // won't individually composite with the background.
+ ctx.globalCompositeOperation = 'screen';
+
+ 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();
+
+ const bitmap = canvas.transferToImageBitmap();
+ self.postMessage(bitmap, bitmap);
+ };
+ </script>
+ <script type="module">
+ const blob = new Blob([document.getElementById('myWorker1').textContent]);
+ const worker = new Worker(URL.createObjectURL(blob));
+ worker.addEventListener('message', msg => {
+ const outputCanvas = document.getElementById('canvas1');
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(msg.data, 0, 0);
+ if (--pending_tests == 0) {
+ document.documentElement.classList.remove('reftest-wait');
+ }
+ });
+ worker.postMessage(null);
+ </script>
+</span>
+
+</div>
+</html>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.no-composite-op.shadow.no-transform-expected.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.no-composite-op.shadow.no-transform-expected.html
new file mode 100644
index 0000000000..02b239116c
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.no-composite-op.shadow.no-transform-expected.html
@@ -0,0 +1,78 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<title>Canvas test: 2d.layer.global-states.no-composite-op.shadow.no-transform</title>
+<h1 style="font-size: 20px;">2d.layer.global-states.no-composite-op.shadow.no-transform</h1>
+<p class="desc">Checks that layers correctly use global render states.</p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(2, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>no-globalAlpha</div>
+ <canvas id="canvas0" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas0");
+ const ctx = canvas.getContext('2d');
+
+ // No transform.
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ // No globalAlpha.
+ // No globalCompositeOperation.
+ ctx.shadowOffsetX = -7;
+ ctx.shadowOffsetY = 7;
+ ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
+ ctx.shadowBlur = 3;
+
+ const canvas2 = document.createElement("canvas");
+ const ctx2 = canvas2.getContext("2d");
+
+ ctx2.globalCompositeOperation = 'screen';
+ ctx2.fillStyle = 'rgba(255, 0, 0, 1)';
+ ctx2.fillRect(10, 25, 40, 50);
+ ctx2.fillStyle = 'rgba(0, 255, 0, 1)';
+ ctx2.fillRect(30, 5, 50, 40);
+
+ ctx.drawImage(canvas2, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>globalAlpha</div>
+ <canvas id="canvas1" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas1");
+ const ctx = canvas.getContext('2d');
+
+ // No transform.
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ ctx.globalAlpha = 0.75;
+ // No globalCompositeOperation.
+ ctx.shadowOffsetX = -7;
+ ctx.shadowOffsetY = 7;
+ ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
+ ctx.shadowBlur = 3;
+
+ const canvas2 = document.createElement("canvas");
+ const ctx2 = canvas2.getContext("2d");
+
+ ctx2.globalCompositeOperation = 'screen';
+ ctx2.fillStyle = 'rgba(255, 0, 0, 1)';
+ ctx2.fillRect(10, 25, 40, 50);
+ ctx2.fillStyle = 'rgba(0, 255, 0, 1)';
+ ctx2.fillRect(30, 5, 50, 40);
+
+ ctx.drawImage(canvas2, 0, 0);
+ </script>
+</span>
+
+</div>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.no-composite-op.shadow.no-transform.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.no-composite-op.shadow.no-transform.html
new file mode 100644
index 0000000000..99301fde09
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.no-composite-op.shadow.no-transform.html
@@ -0,0 +1,91 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<link rel="match" href="2d.layer.global-states.no-composite-op.shadow.no-transform-expected.html">
+<title>Canvas test: 2d.layer.global-states.no-composite-op.shadow.no-transform</title>
+<h1 style="font-size: 20px;">2d.layer.global-states.no-composite-op.shadow.no-transform</h1>
+<p class="desc">Checks that layers correctly use global render states.</p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(2, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>no-globalAlpha</div>
+ <canvas id="canvas0" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(90, 90);
+ const ctx = canvas.getContext('2d');
+
+ // No transform.
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ // No globalAlpha.
+ // No globalCompositeOperation.
+ ctx.shadowOffsetX = -7;
+ ctx.shadowOffsetY = 7;
+ ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
+ ctx.shadowBlur = 3;
+
+ ctx.beginLayer();
+
+ // Enable compositing in the layer to validate that draw calls in the layer
+ // won't individually composite with the background.
+ ctx.globalCompositeOperation = 'screen';
+
+ 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();
+
+ const outputCanvas = document.getElementById("canvas0");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>globalAlpha</div>
+ <canvas id="canvas1" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(90, 90);
+ const ctx = canvas.getContext('2d');
+
+ // No transform.
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ ctx.globalAlpha = 0.75;
+ // No globalCompositeOperation.
+ ctx.shadowOffsetX = -7;
+ ctx.shadowOffsetY = 7;
+ ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
+ ctx.shadowBlur = 3;
+
+ ctx.beginLayer();
+
+ // Enable compositing in the layer to validate that draw calls in the layer
+ // won't individually composite with the background.
+ ctx.globalCompositeOperation = 'screen';
+
+ 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();
+
+ const outputCanvas = document.getElementById("canvas1");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+</div>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.no-composite-op.shadow.no-transform.w.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.no-composite-op.shadow.no-transform.w.html
new file mode 100644
index 0000000000..46375f290c
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.no-composite-op.shadow.no-transform.w.html
@@ -0,0 +1,122 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<html class="reftest-wait">
+<link rel="match" href="2d.layer.global-states.no-composite-op.shadow.no-transform-expected.html">
+<title>Canvas test: 2d.layer.global-states.no-composite-op.shadow.no-transform</title>
+<h1 style="font-size: 20px;">2d.layer.global-states.no-composite-op.shadow.no-transform</h1>
+<p class="desc">Checks that layers correctly use global render states.</p>
+<script>pending_tests = 2;</script>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(2, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>no-globalAlpha</div>
+ <canvas id="canvas0" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script id="myWorker0" type="text/worker">
+ self.onmessage = function(e) {
+ const canvas = new OffscreenCanvas(90, 90);
+ const ctx = canvas.getContext('2d');
+
+ // No transform.
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ // No globalAlpha.
+ // No globalCompositeOperation.
+ ctx.shadowOffsetX = -7;
+ ctx.shadowOffsetY = 7;
+ ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
+ ctx.shadowBlur = 3;
+
+ ctx.beginLayer();
+
+ // Enable compositing in the layer to validate that draw calls in the layer
+ // won't individually composite with the background.
+ ctx.globalCompositeOperation = 'screen';
+
+ 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();
+
+ const bitmap = canvas.transferToImageBitmap();
+ self.postMessage(bitmap, bitmap);
+ };
+ </script>
+ <script type="module">
+ const blob = new Blob([document.getElementById('myWorker0').textContent]);
+ const worker = new Worker(URL.createObjectURL(blob));
+ worker.addEventListener('message', msg => {
+ const outputCanvas = document.getElementById('canvas0');
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(msg.data, 0, 0);
+ if (--pending_tests == 0) {
+ document.documentElement.classList.remove('reftest-wait');
+ }
+ });
+ worker.postMessage(null);
+ </script>
+</span>
+
+<span>
+ <div>globalAlpha</div>
+ <canvas id="canvas1" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script id="myWorker1" type="text/worker">
+ self.onmessage = function(e) {
+ const canvas = new OffscreenCanvas(90, 90);
+ const ctx = canvas.getContext('2d');
+
+ // No transform.
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ ctx.globalAlpha = 0.75;
+ // No globalCompositeOperation.
+ ctx.shadowOffsetX = -7;
+ ctx.shadowOffsetY = 7;
+ ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
+ ctx.shadowBlur = 3;
+
+ ctx.beginLayer();
+
+ // Enable compositing in the layer to validate that draw calls in the layer
+ // won't individually composite with the background.
+ ctx.globalCompositeOperation = 'screen';
+
+ 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();
+
+ const bitmap = canvas.transferToImageBitmap();
+ self.postMessage(bitmap, bitmap);
+ };
+ </script>
+ <script type="module">
+ const blob = new Blob([document.getElementById('myWorker1').textContent]);
+ const worker = new Worker(URL.createObjectURL(blob));
+ worker.addEventListener('message', msg => {
+ const outputCanvas = document.getElementById('canvas1');
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(msg.data, 0, 0);
+ if (--pending_tests == 0) {
+ document.documentElement.classList.remove('reftest-wait');
+ }
+ });
+ worker.postMessage(null);
+ </script>
+</span>
+
+</div>
+</html>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.no-composite-op.shadow.rotation-expected.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.no-composite-op.shadow.rotation-expected.html
new file mode 100644
index 0000000000..06f6a2dff3
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.no-composite-op.shadow.rotation-expected.html
@@ -0,0 +1,82 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<title>Canvas test: 2d.layer.global-states.no-composite-op.shadow.rotation</title>
+<h1 style="font-size: 20px;">2d.layer.global-states.no-composite-op.shadow.rotation</h1>
+<p class="desc">Checks that layers correctly use global render states.</p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(2, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>no-globalAlpha</div>
+ <canvas id="canvas0" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas0");
+ const ctx = canvas.getContext('2d');
+
+ ctx.translate(50, 40);
+ ctx.rotate(Math.PI);
+ ctx.translate(-45, -45);
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ // No globalAlpha.
+ // No globalCompositeOperation.
+ ctx.shadowOffsetX = -7;
+ ctx.shadowOffsetY = 7;
+ ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
+ ctx.shadowBlur = 3;
+
+ const canvas2 = document.createElement("canvas");
+ const ctx2 = canvas2.getContext("2d");
+
+ ctx2.globalCompositeOperation = 'screen';
+ ctx2.fillStyle = 'rgba(255, 0, 0, 1)';
+ ctx2.fillRect(10, 25, 40, 50);
+ ctx2.fillStyle = 'rgba(0, 255, 0, 1)';
+ ctx2.fillRect(30, 5, 50, 40);
+
+ ctx.drawImage(canvas2, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>globalAlpha</div>
+ <canvas id="canvas1" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas1");
+ const ctx = canvas.getContext('2d');
+
+ ctx.translate(50, 40);
+ ctx.rotate(Math.PI);
+ ctx.translate(-45, -45);
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ ctx.globalAlpha = 0.75;
+ // No globalCompositeOperation.
+ ctx.shadowOffsetX = -7;
+ ctx.shadowOffsetY = 7;
+ ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
+ ctx.shadowBlur = 3;
+
+ const canvas2 = document.createElement("canvas");
+ const ctx2 = canvas2.getContext("2d");
+
+ ctx2.globalCompositeOperation = 'screen';
+ ctx2.fillStyle = 'rgba(255, 0, 0, 1)';
+ ctx2.fillRect(10, 25, 40, 50);
+ ctx2.fillStyle = 'rgba(0, 255, 0, 1)';
+ ctx2.fillRect(30, 5, 50, 40);
+
+ ctx.drawImage(canvas2, 0, 0);
+ </script>
+</span>
+
+</div>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.no-composite-op.shadow.rotation.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.no-composite-op.shadow.rotation.html
new file mode 100644
index 0000000000..280cc1cceb
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.no-composite-op.shadow.rotation.html
@@ -0,0 +1,95 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<link rel="match" href="2d.layer.global-states.no-composite-op.shadow.rotation-expected.html">
+<title>Canvas test: 2d.layer.global-states.no-composite-op.shadow.rotation</title>
+<h1 style="font-size: 20px;">2d.layer.global-states.no-composite-op.shadow.rotation</h1>
+<p class="desc">Checks that layers correctly use global render states.</p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(2, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>no-globalAlpha</div>
+ <canvas id="canvas0" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(90, 90);
+ const ctx = canvas.getContext('2d');
+
+ ctx.translate(50, 40);
+ ctx.rotate(Math.PI);
+ ctx.translate(-45, -45);
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ // No globalAlpha.
+ // No globalCompositeOperation.
+ ctx.shadowOffsetX = -7;
+ ctx.shadowOffsetY = 7;
+ ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
+ ctx.shadowBlur = 3;
+
+ ctx.beginLayer();
+
+ // Enable compositing in the layer to validate that draw calls in the layer
+ // won't individually composite with the background.
+ ctx.globalCompositeOperation = 'screen';
+
+ 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();
+
+ const outputCanvas = document.getElementById("canvas0");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>globalAlpha</div>
+ <canvas id="canvas1" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(90, 90);
+ const ctx = canvas.getContext('2d');
+
+ ctx.translate(50, 40);
+ ctx.rotate(Math.PI);
+ ctx.translate(-45, -45);
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ ctx.globalAlpha = 0.75;
+ // No globalCompositeOperation.
+ ctx.shadowOffsetX = -7;
+ ctx.shadowOffsetY = 7;
+ ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
+ ctx.shadowBlur = 3;
+
+ ctx.beginLayer();
+
+ // Enable compositing in the layer to validate that draw calls in the layer
+ // won't individually composite with the background.
+ ctx.globalCompositeOperation = 'screen';
+
+ 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();
+
+ const outputCanvas = document.getElementById("canvas1");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+</div>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.no-composite-op.shadow.rotation.w.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.no-composite-op.shadow.rotation.w.html
new file mode 100644
index 0000000000..3192f79afa
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.no-composite-op.shadow.rotation.w.html
@@ -0,0 +1,126 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<html class="reftest-wait">
+<link rel="match" href="2d.layer.global-states.no-composite-op.shadow.rotation-expected.html">
+<title>Canvas test: 2d.layer.global-states.no-composite-op.shadow.rotation</title>
+<h1 style="font-size: 20px;">2d.layer.global-states.no-composite-op.shadow.rotation</h1>
+<p class="desc">Checks that layers correctly use global render states.</p>
+<script>pending_tests = 2;</script>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(2, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>no-globalAlpha</div>
+ <canvas id="canvas0" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script id="myWorker0" type="text/worker">
+ self.onmessage = function(e) {
+ const canvas = new OffscreenCanvas(90, 90);
+ const ctx = canvas.getContext('2d');
+
+ ctx.translate(50, 40);
+ ctx.rotate(Math.PI);
+ ctx.translate(-45, -45);
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ // No globalAlpha.
+ // No globalCompositeOperation.
+ ctx.shadowOffsetX = -7;
+ ctx.shadowOffsetY = 7;
+ ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
+ ctx.shadowBlur = 3;
+
+ ctx.beginLayer();
+
+ // Enable compositing in the layer to validate that draw calls in the layer
+ // won't individually composite with the background.
+ ctx.globalCompositeOperation = 'screen';
+
+ 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();
+
+ const bitmap = canvas.transferToImageBitmap();
+ self.postMessage(bitmap, bitmap);
+ };
+ </script>
+ <script type="module">
+ const blob = new Blob([document.getElementById('myWorker0').textContent]);
+ const worker = new Worker(URL.createObjectURL(blob));
+ worker.addEventListener('message', msg => {
+ const outputCanvas = document.getElementById('canvas0');
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(msg.data, 0, 0);
+ if (--pending_tests == 0) {
+ document.documentElement.classList.remove('reftest-wait');
+ }
+ });
+ worker.postMessage(null);
+ </script>
+</span>
+
+<span>
+ <div>globalAlpha</div>
+ <canvas id="canvas1" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script id="myWorker1" type="text/worker">
+ self.onmessage = function(e) {
+ const canvas = new OffscreenCanvas(90, 90);
+ const ctx = canvas.getContext('2d');
+
+ ctx.translate(50, 40);
+ ctx.rotate(Math.PI);
+ ctx.translate(-45, -45);
+
+ ctx.fillStyle = 'rgba(128, 128, 128, 1)';
+ ctx.fillRect(20, 15, 50, 50);
+
+ ctx.globalAlpha = 0.75;
+ // No globalCompositeOperation.
+ ctx.shadowOffsetX = -7;
+ ctx.shadowOffsetY = 7;
+ ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
+ ctx.shadowBlur = 3;
+
+ ctx.beginLayer();
+
+ // Enable compositing in the layer to validate that draw calls in the layer
+ // won't individually composite with the background.
+ ctx.globalCompositeOperation = 'screen';
+
+ 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();
+
+ const bitmap = canvas.transferToImageBitmap();
+ self.postMessage(bitmap, bitmap);
+ };
+ </script>
+ <script type="module">
+ const blob = new Blob([document.getElementById('myWorker1').textContent]);
+ const worker = new Worker(URL.createObjectURL(blob));
+ worker.addEventListener('message', msg => {
+ const outputCanvas = document.getElementById('canvas1');
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(msg.data, 0, 0);
+ if (--pending_tests == 0) {
+ document.documentElement.classList.remove('reftest-wait');
+ }
+ });
+ worker.postMessage(null);
+ </script>
+</span>
+
+</div>
+</html>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.no-global-states-expected.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.no-global-states-expected.html
deleted file mode 100644
index b91a2ae8b5..0000000000
--- a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.no-global-states-expected.html
+++ /dev/null
@@ -1,31 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<title>Canvas test: 2d.layer.global-states.no-global-states</title>
-<h1>2d.layer.global-states.no-global-states</h1>
-<p class="desc">Checks that layers correctly use global render states.</p>
-<canvas id="canvas" width="200" height="200">
- <p class="fallback">FAIL (fallback content)</p>
-</canvas>
-<script>
- const canvas = document.getElementById("canvas");
- const ctx = canvas.getContext('2d');
-
- ctx.fillStyle = 'rgba(0, 0, 255, 1)';
-
- var circle = new Path2D();
- circle.arc(90, 90, 45, 0, 2 * Math.PI);
- ctx.fill(circle);
-
- // No global states.
-
- canvas2 = document.createElement("canvas");
- ctx2 = canvas2.getContext("2d");
-
- ctx2.globalCompositeOperation = 'screen';
- ctx2.fillStyle = 'rgba(225, 0, 0, 1)';
- ctx2.fillRect(50, 50, 75, 50);
- ctx2.fillStyle = 'rgba(0, 255, 0, 1)';
- ctx2.fillRect(70, 70, 75, 50);
-
- ctx.drawImage(canvas2, 0, 0);
-</script>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.no-global-states.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.no-global-states.html
deleted file mode 100644
index c8a9815381..0000000000
--- a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.no-global-states.html
+++ /dev/null
@@ -1,37 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<link rel="match" href="2d.layer.global-states.no-global-states-expected.html">
-<title>Canvas test: 2d.layer.global-states.no-global-states</title>
-<h1>2d.layer.global-states.no-global-states</h1>
-<p class="desc">Checks that layers correctly use global render states.</p>
-<canvas id="canvas" width="200" height="200">
- <p class="fallback">FAIL (fallback content)</p>
-</canvas>
-<script>
- const canvas = new OffscreenCanvas(200, 200);
- const ctx = canvas.getContext('2d');
-
- ctx.fillStyle = 'rgba(0, 0, 255, 1)';
-
- var circle = new Path2D();
- circle.arc(90, 90, 45, 0, 2 * Math.PI);
- ctx.fill(circle);
-
- // No global states.
-
- ctx.beginLayer();
-
- // Enable compositing in the layer to validate that draw calls in the layer
- // 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(0, 255, 0, 1)';
- ctx.fillRect(70, 70, 75, 50);
-
- ctx.endLayer();
-
- const outputCanvas = document.getElementById("canvas");
- outputCanvas.getContext('2d').drawImage(canvas, 0, 0);
-</script>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.no-global-states.w.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.no-global-states.w.html
deleted file mode 100644
index db03a3fd0c..0000000000
--- a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.no-global-states.w.html
+++ /dev/null
@@ -1,51 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<html class="reftest-wait">
-<link rel="match" href="2d.layer.global-states.no-global-states-expected.html">
-<title>Canvas test: 2d.layer.global-states.no-global-states</title>
-<h1>2d.layer.global-states.no-global-states</h1>
-<p class="desc">Checks that layers correctly use global render states.</p>
-<canvas id="canvas" width="200" height="200">
- <p class="fallback">FAIL (fallback content)</p>
-</canvas>
-<script id='myWorker' type='text/worker'>
- self.onmessage = function(e) {
- const canvas = new OffscreenCanvas(200, 200);
- const ctx = canvas.getContext('2d');
-
- ctx.fillStyle = 'rgba(0, 0, 255, 1)';
-
- var circle = new Path2D();
- circle.arc(90, 90, 45, 0, 2 * Math.PI);
- ctx.fill(circle);
-
- // No global states.
-
- ctx.beginLayer();
-
- // Enable compositing in the layer to validate that draw calls in the layer
- // 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(0, 255, 0, 1)';
- ctx.fillRect(70, 70, 75, 50);
-
- ctx.endLayer();
-
- const bitmap = canvas.transferToImageBitmap();
- self.postMessage(bitmap, bitmap);
- };
-</script>
-<script>
- const blob = new Blob([document.getElementById('myWorker').textContent]);
- const worker = new Worker(URL.createObjectURL(blob));
- worker.addEventListener('message', msg => {
- const outputCtx = document.getElementById("canvas").getContext('2d');
- outputCtx.drawImage(msg.data, 0, 0);
- document.documentElement.classList.remove("reftest-wait");
- });
- worker.postMessage(null);
-</script>
-</html>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.shadow-expected.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.shadow-expected.html
deleted file mode 100644
index 835e9d420a..0000000000
--- a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.shadow-expected.html
+++ /dev/null
@@ -1,34 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<title>Canvas test: 2d.layer.global-states.shadow</title>
-<h1>2d.layer.global-states.shadow</h1>
-<p class="desc">Checks that layers correctly use global render states.</p>
-<canvas id="canvas" width="200" height="200">
- <p class="fallback">FAIL (fallback content)</p>
-</canvas>
-<script>
- const canvas = document.getElementById("canvas");
- const ctx = canvas.getContext('2d');
-
- ctx.fillStyle = 'rgba(0, 0, 255, 1)';
-
- var circle = new Path2D();
- circle.arc(90, 90, 45, 0, 2 * Math.PI);
- ctx.fill(circle);
-
- ctx.shadowOffsetX = -10;
- ctx.shadowOffsetY = 10;
- ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
- ctx.shadowBlur = 3;
-
- canvas2 = document.createElement("canvas");
- ctx2 = canvas2.getContext("2d");
-
- ctx2.globalCompositeOperation = 'screen';
- ctx2.fillStyle = 'rgba(225, 0, 0, 1)';
- ctx2.fillRect(50, 50, 75, 50);
- ctx2.fillStyle = 'rgba(0, 255, 0, 1)';
- ctx2.fillRect(70, 70, 75, 50);
-
- ctx.drawImage(canvas2, 0, 0);
-</script>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.shadow.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.shadow.html
deleted file mode 100644
index ad60e87fb1..0000000000
--- a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.shadow.html
+++ /dev/null
@@ -1,40 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<link rel="match" href="2d.layer.global-states.shadow-expected.html">
-<title>Canvas test: 2d.layer.global-states.shadow</title>
-<h1>2d.layer.global-states.shadow</h1>
-<p class="desc">Checks that layers correctly use global render states.</p>
-<canvas id="canvas" width="200" height="200">
- <p class="fallback">FAIL (fallback content)</p>
-</canvas>
-<script>
- const canvas = new OffscreenCanvas(200, 200);
- const ctx = canvas.getContext('2d');
-
- ctx.fillStyle = 'rgba(0, 0, 255, 1)';
-
- var circle = new Path2D();
- circle.arc(90, 90, 45, 0, 2 * Math.PI);
- ctx.fill(circle);
-
- ctx.shadowOffsetX = -10;
- ctx.shadowOffsetY = 10;
- ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
- ctx.shadowBlur = 3;
-
- ctx.beginLayer();
-
- // Enable compositing in the layer to validate that draw calls in the layer
- // 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(0, 255, 0, 1)';
- ctx.fillRect(70, 70, 75, 50);
-
- ctx.endLayer();
-
- const outputCanvas = document.getElementById("canvas");
- outputCanvas.getContext('2d').drawImage(canvas, 0, 0);
-</script>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.shadow.w.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.shadow.w.html
deleted file mode 100644
index 1fc35fd33a..0000000000
--- a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.global-states.shadow.w.html
+++ /dev/null
@@ -1,54 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<html class="reftest-wait">
-<link rel="match" href="2d.layer.global-states.shadow-expected.html">
-<title>Canvas test: 2d.layer.global-states.shadow</title>
-<h1>2d.layer.global-states.shadow</h1>
-<p class="desc">Checks that layers correctly use global render states.</p>
-<canvas id="canvas" width="200" height="200">
- <p class="fallback">FAIL (fallback content)</p>
-</canvas>
-<script id='myWorker' type='text/worker'>
- self.onmessage = function(e) {
- const canvas = new OffscreenCanvas(200, 200);
- const ctx = canvas.getContext('2d');
-
- ctx.fillStyle = 'rgba(0, 0, 255, 1)';
-
- var circle = new Path2D();
- circle.arc(90, 90, 45, 0, 2 * Math.PI);
- ctx.fill(circle);
-
- ctx.shadowOffsetX = -10;
- ctx.shadowOffsetY = 10;
- ctx.shadowColor = 'rgba(255, 165, 0, 0.5)';
- ctx.shadowBlur = 3;
-
- ctx.beginLayer();
-
- // Enable compositing in the layer to validate that draw calls in the layer
- // 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(0, 255, 0, 1)';
- ctx.fillRect(70, 70, 75, 50);
-
- ctx.endLayer();
-
- const bitmap = canvas.transferToImageBitmap();
- self.postMessage(bitmap, bitmap);
- };
-</script>
-<script>
- const blob = new Blob([document.getElementById('myWorker').textContent]);
- const worker = new Worker(URL.createObjectURL(blob));
- worker.addEventListener('message', msg => {
- const outputCtx = document.getElementById("canvas").getContext('2d');
- outputCtx.drawImage(msg.data, 0, 0);
- document.documentElement.classList.remove("reftest-wait");
- });
- worker.postMessage(null);
-</script>
-</html>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.globalCompositeOperation-expected.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.globalCompositeOperation-expected.html
new file mode 100644
index 0000000000..02a8915c0b
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.globalCompositeOperation-expected.html
@@ -0,0 +1,910 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<title>Canvas test: 2d.layer.globalCompositeOperation</title>
+<h1 style="font-size: 20px;">2d.layer.globalCompositeOperation</h1>
+<p class="desc">Checks that layers work with all globalCompositeOperation values.</p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(7, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>source-over</div>
+ <canvas id="canvas0" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas0");
+ const ctx = canvas.getContext('2d');
+
+ 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 = 'source-over';
+ 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);
+ </script>
+</span>
+
+<span>
+ <div>source-in</div>
+ <canvas id="canvas1" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas1");
+ const ctx = canvas.getContext('2d');
+
+ 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 = 'source-in';
+ 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);
+ </script>
+</span>
+
+<span>
+ <div>source-atop</div>
+ <canvas id="canvas2" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas2");
+ const ctx = canvas.getContext('2d');
+
+ 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 = 'source-atop';
+ 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);
+ </script>
+</span>
+
+<span>
+ <div>destination-over</div>
+ <canvas id="canvas3" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas3");
+ const ctx = canvas.getContext('2d');
+
+ 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 = 'destination-over';
+ 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);
+ </script>
+</span>
+
+<span>
+ <div>destination-in</div>
+ <canvas id="canvas4" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas4");
+ const ctx = canvas.getContext('2d');
+
+ 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 = 'destination-in';
+ 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);
+ </script>
+</span>
+
+<span>
+ <div>destination-out</div>
+ <canvas id="canvas5" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas5");
+ const ctx = canvas.getContext('2d');
+
+ 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 = 'destination-out';
+ 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);
+ </script>
+</span>
+
+<span>
+ <div>destination-atop</div>
+ <canvas id="canvas6" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas6");
+ const ctx = canvas.getContext('2d');
+
+ 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 = 'destination-atop';
+ 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);
+ </script>
+</span>
+
+<span>
+ <div>lighter</div>
+ <canvas id="canvas7" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas7");
+ const ctx = canvas.getContext('2d');
+
+ 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 = 'lighter';
+ 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);
+ </script>
+</span>
+
+<span>
+ <div>copy</div>
+ <canvas id="canvas8" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas8");
+ const ctx = canvas.getContext('2d');
+
+ 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 = 'copy';
+ 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);
+ </script>
+</span>
+
+<span>
+ <div>xor</div>
+ <canvas id="canvas9" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas9");
+ const ctx = canvas.getContext('2d');
+
+ 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 = 'xor';
+ 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);
+ </script>
+</span>
+
+<span>
+ <div>multiply</div>
+ <canvas id="canvas10" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas10");
+ const ctx = canvas.getContext('2d');
+
+ 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 = 'multiply';
+ 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);
+ </script>
+</span>
+
+<span>
+ <div>screen</div>
+ <canvas id="canvas11" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas11");
+ const ctx = canvas.getContext('2d');
+
+ 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 = 'screen';
+ 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);
+ </script>
+</span>
+
+<span>
+ <div>overlay</div>
+ <canvas id="canvas12" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas12");
+ const ctx = canvas.getContext('2d');
+
+ 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 = 'overlay';
+ 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);
+ </script>
+</span>
+
+<span>
+ <div>darken</div>
+ <canvas id="canvas13" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas13");
+ const ctx = canvas.getContext('2d');
+
+ 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 = 'darken';
+ 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);
+ </script>
+</span>
+
+<span>
+ <div>lighten</div>
+ <canvas id="canvas14" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas14");
+ const ctx = canvas.getContext('2d');
+
+ 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 = 'lighten';
+ 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);
+ </script>
+</span>
+
+<span>
+ <div>color-dodge</div>
+ <canvas id="canvas15" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas15");
+ const ctx = canvas.getContext('2d');
+
+ 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 = 'color-dodge';
+ 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);
+ </script>
+</span>
+
+<span>
+ <div>color-burn</div>
+ <canvas id="canvas16" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas16");
+ const ctx = canvas.getContext('2d');
+
+ 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 = 'color-burn';
+ 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);
+ </script>
+</span>
+
+<span>
+ <div>hard-light</div>
+ <canvas id="canvas17" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas17");
+ const ctx = canvas.getContext('2d');
+
+ 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 = 'hard-light';
+ 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);
+ </script>
+</span>
+
+<span>
+ <div>soft-light</div>
+ <canvas id="canvas18" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas18");
+ const ctx = canvas.getContext('2d');
+
+ 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 = 'soft-light';
+ 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);
+ </script>
+</span>
+
+<span>
+ <div>difference</div>
+ <canvas id="canvas19" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas19");
+ const ctx = canvas.getContext('2d');
+
+ 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 = 'difference';
+ 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);
+ </script>
+</span>
+
+<span>
+ <div>exclusion</div>
+ <canvas id="canvas20" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas20");
+ const ctx = canvas.getContext('2d');
+
+ 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 = 'exclusion';
+ 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);
+ </script>
+</span>
+
+<span>
+ <div>hue</div>
+ <canvas id="canvas21" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas21");
+ const ctx = canvas.getContext('2d');
+
+ 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 = 'hue';
+ 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);
+ </script>
+</span>
+
+<span>
+ <div>saturation</div>
+ <canvas id="canvas22" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas22");
+ const ctx = canvas.getContext('2d');
+
+ 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 = 'saturation';
+ 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);
+ </script>
+</span>
+
+<span>
+ <div>color</div>
+ <canvas id="canvas23" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas23");
+ const ctx = canvas.getContext('2d');
+
+ 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 = 'color';
+ 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);
+ </script>
+</span>
+
+<span>
+ <div>luminosity</div>
+ <canvas id="canvas24" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas24");
+ const ctx = canvas.getContext('2d');
+
+ 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 = 'luminosity';
+ 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);
+ </script>
+</span>
+
+</div>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.globalCompositeOperation.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.globalCompositeOperation.html
new file mode 100644
index 0000000000..ab9bc4270b
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.globalCompositeOperation.html
@@ -0,0 +1,961 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<link rel="match" href="2d.layer.globalCompositeOperation-expected.html">
+<title>Canvas test: 2d.layer.globalCompositeOperation</title>
+<h1 style="font-size: 20px;">2d.layer.globalCompositeOperation</h1>
+<p class="desc">Checks that layers work with all globalCompositeOperation values.</p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(7, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>source-over</div>
+ <canvas id="canvas0" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(90, 90);
+ const ctx = canvas.getContext('2d');
+
+ 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 = 'source-over';
+ 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();
+
+ const outputCanvas = document.getElementById("canvas0");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>source-in</div>
+ <canvas id="canvas1" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(90, 90);
+ const ctx = canvas.getContext('2d');
+
+ 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 = 'source-in';
+ 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();
+
+ const outputCanvas = document.getElementById("canvas1");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>source-atop</div>
+ <canvas id="canvas2" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(90, 90);
+ const ctx = canvas.getContext('2d');
+
+ 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 = 'source-atop';
+ 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();
+
+ const outputCanvas = document.getElementById("canvas2");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>destination-over</div>
+ <canvas id="canvas3" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(90, 90);
+ const ctx = canvas.getContext('2d');
+
+ 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 = 'destination-over';
+ 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();
+
+ const outputCanvas = document.getElementById("canvas3");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>destination-in</div>
+ <canvas id="canvas4" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(90, 90);
+ const ctx = canvas.getContext('2d');
+
+ 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 = 'destination-in';
+ 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();
+
+ const outputCanvas = document.getElementById("canvas4");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>destination-out</div>
+ <canvas id="canvas5" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(90, 90);
+ const ctx = canvas.getContext('2d');
+
+ 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 = 'destination-out';
+ 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();
+
+ const outputCanvas = document.getElementById("canvas5");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>destination-atop</div>
+ <canvas id="canvas6" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(90, 90);
+ const ctx = canvas.getContext('2d');
+
+ 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 = 'destination-atop';
+ 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();
+
+ const outputCanvas = document.getElementById("canvas6");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>lighter</div>
+ <canvas id="canvas7" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(90, 90);
+ const ctx = canvas.getContext('2d');
+
+ 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 = 'lighter';
+ 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();
+
+ const outputCanvas = document.getElementById("canvas7");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>copy</div>
+ <canvas id="canvas8" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(90, 90);
+ const ctx = canvas.getContext('2d');
+
+ 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 = 'copy';
+ 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();
+
+ const outputCanvas = document.getElementById("canvas8");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>xor</div>
+ <canvas id="canvas9" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(90, 90);
+ const ctx = canvas.getContext('2d');
+
+ 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 = 'xor';
+ 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();
+
+ const outputCanvas = document.getElementById("canvas9");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>multiply</div>
+ <canvas id="canvas10" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(90, 90);
+ const ctx = canvas.getContext('2d');
+
+ 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 = 'multiply';
+ 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();
+
+ const outputCanvas = document.getElementById("canvas10");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>screen</div>
+ <canvas id="canvas11" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(90, 90);
+ const ctx = canvas.getContext('2d');
+
+ 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 = 'screen';
+ 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();
+
+ const outputCanvas = document.getElementById("canvas11");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>overlay</div>
+ <canvas id="canvas12" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(90, 90);
+ const ctx = canvas.getContext('2d');
+
+ 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 = 'overlay';
+ 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();
+
+ const outputCanvas = document.getElementById("canvas12");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>darken</div>
+ <canvas id="canvas13" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(90, 90);
+ const ctx = canvas.getContext('2d');
+
+ 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 = 'darken';
+ 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();
+
+ const outputCanvas = document.getElementById("canvas13");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>lighten</div>
+ <canvas id="canvas14" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(90, 90);
+ const ctx = canvas.getContext('2d');
+
+ 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 = 'lighten';
+ 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();
+
+ const outputCanvas = document.getElementById("canvas14");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>color-dodge</div>
+ <canvas id="canvas15" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(90, 90);
+ const ctx = canvas.getContext('2d');
+
+ 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 = 'color-dodge';
+ 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();
+
+ const outputCanvas = document.getElementById("canvas15");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>color-burn</div>
+ <canvas id="canvas16" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(90, 90);
+ const ctx = canvas.getContext('2d');
+
+ 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 = 'color-burn';
+ 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();
+
+ const outputCanvas = document.getElementById("canvas16");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>hard-light</div>
+ <canvas id="canvas17" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(90, 90);
+ const ctx = canvas.getContext('2d');
+
+ 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 = 'hard-light';
+ 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();
+
+ const outputCanvas = document.getElementById("canvas17");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>soft-light</div>
+ <canvas id="canvas18" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(90, 90);
+ const ctx = canvas.getContext('2d');
+
+ 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 = 'soft-light';
+ 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();
+
+ const outputCanvas = document.getElementById("canvas18");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>difference</div>
+ <canvas id="canvas19" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(90, 90);
+ const ctx = canvas.getContext('2d');
+
+ 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 = 'difference';
+ 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();
+
+ const outputCanvas = document.getElementById("canvas19");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>exclusion</div>
+ <canvas id="canvas20" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(90, 90);
+ const ctx = canvas.getContext('2d');
+
+ 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 = 'exclusion';
+ 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();
+
+ const outputCanvas = document.getElementById("canvas20");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>hue</div>
+ <canvas id="canvas21" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(90, 90);
+ const ctx = canvas.getContext('2d');
+
+ 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 = 'hue';
+ 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();
+
+ const outputCanvas = document.getElementById("canvas21");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>saturation</div>
+ <canvas id="canvas22" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(90, 90);
+ const ctx = canvas.getContext('2d');
+
+ 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 = 'saturation';
+ 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();
+
+ const outputCanvas = document.getElementById("canvas22");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>color</div>
+ <canvas id="canvas23" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(90, 90);
+ const ctx = canvas.getContext('2d');
+
+ 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 = 'color';
+ 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();
+
+ const outputCanvas = document.getElementById("canvas23");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>luminosity</div>
+ <canvas id="canvas24" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(90, 90);
+ const ctx = canvas.getContext('2d');
+
+ 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 = 'luminosity';
+ 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();
+
+ const outputCanvas = document.getElementById("canvas24");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+</div>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.globalCompositeOperation.w.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.globalCompositeOperation.w.html
new file mode 100644
index 0000000000..9a403140fc
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.globalCompositeOperation.w.html
@@ -0,0 +1,1314 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<html class="reftest-wait">
+<link rel="match" href="2d.layer.globalCompositeOperation-expected.html">
+<title>Canvas test: 2d.layer.globalCompositeOperation</title>
+<h1 style="font-size: 20px;">2d.layer.globalCompositeOperation</h1>
+<p class="desc">Checks that layers work with all globalCompositeOperation values.</p>
+<script>pending_tests = 25;</script>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(7, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>source-over</div>
+ <canvas id="canvas0" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script id="myWorker0" type="text/worker">
+ self.onmessage = function(e) {
+ const canvas = new OffscreenCanvas(90, 90);
+ const ctx = canvas.getContext('2d');
+
+ 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 = 'source-over';
+ 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();
+
+ const bitmap = canvas.transferToImageBitmap();
+ self.postMessage(bitmap, bitmap);
+ };
+ </script>
+ <script type="module">
+ const blob = new Blob([document.getElementById('myWorker0').textContent]);
+ const worker = new Worker(URL.createObjectURL(blob));
+ worker.addEventListener('message', msg => {
+ const outputCanvas = document.getElementById('canvas0');
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(msg.data, 0, 0);
+ if (--pending_tests == 0) {
+ document.documentElement.classList.remove('reftest-wait');
+ }
+ });
+ worker.postMessage(null);
+ </script>
+</span>
+
+<span>
+ <div>source-in</div>
+ <canvas id="canvas1" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script id="myWorker1" type="text/worker">
+ self.onmessage = function(e) {
+ const canvas = new OffscreenCanvas(90, 90);
+ const ctx = canvas.getContext('2d');
+
+ 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 = 'source-in';
+ 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();
+
+ const bitmap = canvas.transferToImageBitmap();
+ self.postMessage(bitmap, bitmap);
+ };
+ </script>
+ <script type="module">
+ const blob = new Blob([document.getElementById('myWorker1').textContent]);
+ const worker = new Worker(URL.createObjectURL(blob));
+ worker.addEventListener('message', msg => {
+ const outputCanvas = document.getElementById('canvas1');
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(msg.data, 0, 0);
+ if (--pending_tests == 0) {
+ document.documentElement.classList.remove('reftest-wait');
+ }
+ });
+ worker.postMessage(null);
+ </script>
+</span>
+
+<span>
+ <div>source-atop</div>
+ <canvas id="canvas2" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script id="myWorker2" type="text/worker">
+ self.onmessage = function(e) {
+ const canvas = new OffscreenCanvas(90, 90);
+ const ctx = canvas.getContext('2d');
+
+ 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 = 'source-atop';
+ 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();
+
+ const bitmap = canvas.transferToImageBitmap();
+ self.postMessage(bitmap, bitmap);
+ };
+ </script>
+ <script type="module">
+ const blob = new Blob([document.getElementById('myWorker2').textContent]);
+ const worker = new Worker(URL.createObjectURL(blob));
+ worker.addEventListener('message', msg => {
+ const outputCanvas = document.getElementById('canvas2');
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(msg.data, 0, 0);
+ if (--pending_tests == 0) {
+ document.documentElement.classList.remove('reftest-wait');
+ }
+ });
+ worker.postMessage(null);
+ </script>
+</span>
+
+<span>
+ <div>destination-over</div>
+ <canvas id="canvas3" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script id="myWorker3" type="text/worker">
+ self.onmessage = function(e) {
+ const canvas = new OffscreenCanvas(90, 90);
+ const ctx = canvas.getContext('2d');
+
+ 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 = 'destination-over';
+ 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();
+
+ const bitmap = canvas.transferToImageBitmap();
+ self.postMessage(bitmap, bitmap);
+ };
+ </script>
+ <script type="module">
+ const blob = new Blob([document.getElementById('myWorker3').textContent]);
+ const worker = new Worker(URL.createObjectURL(blob));
+ worker.addEventListener('message', msg => {
+ const outputCanvas = document.getElementById('canvas3');
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(msg.data, 0, 0);
+ if (--pending_tests == 0) {
+ document.documentElement.classList.remove('reftest-wait');
+ }
+ });
+ worker.postMessage(null);
+ </script>
+</span>
+
+<span>
+ <div>destination-in</div>
+ <canvas id="canvas4" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script id="myWorker4" type="text/worker">
+ self.onmessage = function(e) {
+ const canvas = new OffscreenCanvas(90, 90);
+ const ctx = canvas.getContext('2d');
+
+ 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 = 'destination-in';
+ 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();
+
+ const bitmap = canvas.transferToImageBitmap();
+ self.postMessage(bitmap, bitmap);
+ };
+ </script>
+ <script type="module">
+ const blob = new Blob([document.getElementById('myWorker4').textContent]);
+ const worker = new Worker(URL.createObjectURL(blob));
+ worker.addEventListener('message', msg => {
+ const outputCanvas = document.getElementById('canvas4');
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(msg.data, 0, 0);
+ if (--pending_tests == 0) {
+ document.documentElement.classList.remove('reftest-wait');
+ }
+ });
+ worker.postMessage(null);
+ </script>
+</span>
+
+<span>
+ <div>destination-out</div>
+ <canvas id="canvas5" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script id="myWorker5" type="text/worker">
+ self.onmessage = function(e) {
+ const canvas = new OffscreenCanvas(90, 90);
+ const ctx = canvas.getContext('2d');
+
+ 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 = 'destination-out';
+ 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();
+
+ const bitmap = canvas.transferToImageBitmap();
+ self.postMessage(bitmap, bitmap);
+ };
+ </script>
+ <script type="module">
+ const blob = new Blob([document.getElementById('myWorker5').textContent]);
+ const worker = new Worker(URL.createObjectURL(blob));
+ worker.addEventListener('message', msg => {
+ const outputCanvas = document.getElementById('canvas5');
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(msg.data, 0, 0);
+ if (--pending_tests == 0) {
+ document.documentElement.classList.remove('reftest-wait');
+ }
+ });
+ worker.postMessage(null);
+ </script>
+</span>
+
+<span>
+ <div>destination-atop</div>
+ <canvas id="canvas6" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script id="myWorker6" type="text/worker">
+ self.onmessage = function(e) {
+ const canvas = new OffscreenCanvas(90, 90);
+ const ctx = canvas.getContext('2d');
+
+ 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 = 'destination-atop';
+ 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();
+
+ const bitmap = canvas.transferToImageBitmap();
+ self.postMessage(bitmap, bitmap);
+ };
+ </script>
+ <script type="module">
+ const blob = new Blob([document.getElementById('myWorker6').textContent]);
+ const worker = new Worker(URL.createObjectURL(blob));
+ worker.addEventListener('message', msg => {
+ const outputCanvas = document.getElementById('canvas6');
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(msg.data, 0, 0);
+ if (--pending_tests == 0) {
+ document.documentElement.classList.remove('reftest-wait');
+ }
+ });
+ worker.postMessage(null);
+ </script>
+</span>
+
+<span>
+ <div>lighter</div>
+ <canvas id="canvas7" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script id="myWorker7" type="text/worker">
+ self.onmessage = function(e) {
+ const canvas = new OffscreenCanvas(90, 90);
+ const ctx = canvas.getContext('2d');
+
+ 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 = 'lighter';
+ 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();
+
+ const bitmap = canvas.transferToImageBitmap();
+ self.postMessage(bitmap, bitmap);
+ };
+ </script>
+ <script type="module">
+ const blob = new Blob([document.getElementById('myWorker7').textContent]);
+ const worker = new Worker(URL.createObjectURL(blob));
+ worker.addEventListener('message', msg => {
+ const outputCanvas = document.getElementById('canvas7');
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(msg.data, 0, 0);
+ if (--pending_tests == 0) {
+ document.documentElement.classList.remove('reftest-wait');
+ }
+ });
+ worker.postMessage(null);
+ </script>
+</span>
+
+<span>
+ <div>copy</div>
+ <canvas id="canvas8" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script id="myWorker8" type="text/worker">
+ self.onmessage = function(e) {
+ const canvas = new OffscreenCanvas(90, 90);
+ const ctx = canvas.getContext('2d');
+
+ 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 = 'copy';
+ 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();
+
+ const bitmap = canvas.transferToImageBitmap();
+ self.postMessage(bitmap, bitmap);
+ };
+ </script>
+ <script type="module">
+ const blob = new Blob([document.getElementById('myWorker8').textContent]);
+ const worker = new Worker(URL.createObjectURL(blob));
+ worker.addEventListener('message', msg => {
+ const outputCanvas = document.getElementById('canvas8');
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(msg.data, 0, 0);
+ if (--pending_tests == 0) {
+ document.documentElement.classList.remove('reftest-wait');
+ }
+ });
+ worker.postMessage(null);
+ </script>
+</span>
+
+<span>
+ <div>xor</div>
+ <canvas id="canvas9" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script id="myWorker9" type="text/worker">
+ self.onmessage = function(e) {
+ const canvas = new OffscreenCanvas(90, 90);
+ const ctx = canvas.getContext('2d');
+
+ 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 = 'xor';
+ 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();
+
+ const bitmap = canvas.transferToImageBitmap();
+ self.postMessage(bitmap, bitmap);
+ };
+ </script>
+ <script type="module">
+ const blob = new Blob([document.getElementById('myWorker9').textContent]);
+ const worker = new Worker(URL.createObjectURL(blob));
+ worker.addEventListener('message', msg => {
+ const outputCanvas = document.getElementById('canvas9');
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(msg.data, 0, 0);
+ if (--pending_tests == 0) {
+ document.documentElement.classList.remove('reftest-wait');
+ }
+ });
+ worker.postMessage(null);
+ </script>
+</span>
+
+<span>
+ <div>multiply</div>
+ <canvas id="canvas10" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script id="myWorker10" type="text/worker">
+ self.onmessage = function(e) {
+ const canvas = new OffscreenCanvas(90, 90);
+ const ctx = canvas.getContext('2d');
+
+ 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 = 'multiply';
+ 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();
+
+ const bitmap = canvas.transferToImageBitmap();
+ self.postMessage(bitmap, bitmap);
+ };
+ </script>
+ <script type="module">
+ const blob = new Blob([document.getElementById('myWorker10').textContent]);
+ const worker = new Worker(URL.createObjectURL(blob));
+ worker.addEventListener('message', msg => {
+ const outputCanvas = document.getElementById('canvas10');
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(msg.data, 0, 0);
+ if (--pending_tests == 0) {
+ document.documentElement.classList.remove('reftest-wait');
+ }
+ });
+ worker.postMessage(null);
+ </script>
+</span>
+
+<span>
+ <div>screen</div>
+ <canvas id="canvas11" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script id="myWorker11" type="text/worker">
+ self.onmessage = function(e) {
+ const canvas = new OffscreenCanvas(90, 90);
+ const ctx = canvas.getContext('2d');
+
+ 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 = 'screen';
+ 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();
+
+ const bitmap = canvas.transferToImageBitmap();
+ self.postMessage(bitmap, bitmap);
+ };
+ </script>
+ <script type="module">
+ const blob = new Blob([document.getElementById('myWorker11').textContent]);
+ const worker = new Worker(URL.createObjectURL(blob));
+ worker.addEventListener('message', msg => {
+ const outputCanvas = document.getElementById('canvas11');
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(msg.data, 0, 0);
+ if (--pending_tests == 0) {
+ document.documentElement.classList.remove('reftest-wait');
+ }
+ });
+ worker.postMessage(null);
+ </script>
+</span>
+
+<span>
+ <div>overlay</div>
+ <canvas id="canvas12" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script id="myWorker12" type="text/worker">
+ self.onmessage = function(e) {
+ const canvas = new OffscreenCanvas(90, 90);
+ const ctx = canvas.getContext('2d');
+
+ 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 = 'overlay';
+ 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();
+
+ const bitmap = canvas.transferToImageBitmap();
+ self.postMessage(bitmap, bitmap);
+ };
+ </script>
+ <script type="module">
+ const blob = new Blob([document.getElementById('myWorker12').textContent]);
+ const worker = new Worker(URL.createObjectURL(blob));
+ worker.addEventListener('message', msg => {
+ const outputCanvas = document.getElementById('canvas12');
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(msg.data, 0, 0);
+ if (--pending_tests == 0) {
+ document.documentElement.classList.remove('reftest-wait');
+ }
+ });
+ worker.postMessage(null);
+ </script>
+</span>
+
+<span>
+ <div>darken</div>
+ <canvas id="canvas13" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script id="myWorker13" type="text/worker">
+ self.onmessage = function(e) {
+ const canvas = new OffscreenCanvas(90, 90);
+ const ctx = canvas.getContext('2d');
+
+ 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 = 'darken';
+ 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();
+
+ const bitmap = canvas.transferToImageBitmap();
+ self.postMessage(bitmap, bitmap);
+ };
+ </script>
+ <script type="module">
+ const blob = new Blob([document.getElementById('myWorker13').textContent]);
+ const worker = new Worker(URL.createObjectURL(blob));
+ worker.addEventListener('message', msg => {
+ const outputCanvas = document.getElementById('canvas13');
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(msg.data, 0, 0);
+ if (--pending_tests == 0) {
+ document.documentElement.classList.remove('reftest-wait');
+ }
+ });
+ worker.postMessage(null);
+ </script>
+</span>
+
+<span>
+ <div>lighten</div>
+ <canvas id="canvas14" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script id="myWorker14" type="text/worker">
+ self.onmessage = function(e) {
+ const canvas = new OffscreenCanvas(90, 90);
+ const ctx = canvas.getContext('2d');
+
+ 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 = 'lighten';
+ 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();
+
+ const bitmap = canvas.transferToImageBitmap();
+ self.postMessage(bitmap, bitmap);
+ };
+ </script>
+ <script type="module">
+ const blob = new Blob([document.getElementById('myWorker14').textContent]);
+ const worker = new Worker(URL.createObjectURL(blob));
+ worker.addEventListener('message', msg => {
+ const outputCanvas = document.getElementById('canvas14');
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(msg.data, 0, 0);
+ if (--pending_tests == 0) {
+ document.documentElement.classList.remove('reftest-wait');
+ }
+ });
+ worker.postMessage(null);
+ </script>
+</span>
+
+<span>
+ <div>color-dodge</div>
+ <canvas id="canvas15" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script id="myWorker15" type="text/worker">
+ self.onmessage = function(e) {
+ const canvas = new OffscreenCanvas(90, 90);
+ const ctx = canvas.getContext('2d');
+
+ 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 = 'color-dodge';
+ 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();
+
+ const bitmap = canvas.transferToImageBitmap();
+ self.postMessage(bitmap, bitmap);
+ };
+ </script>
+ <script type="module">
+ const blob = new Blob([document.getElementById('myWorker15').textContent]);
+ const worker = new Worker(URL.createObjectURL(blob));
+ worker.addEventListener('message', msg => {
+ const outputCanvas = document.getElementById('canvas15');
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(msg.data, 0, 0);
+ if (--pending_tests == 0) {
+ document.documentElement.classList.remove('reftest-wait');
+ }
+ });
+ worker.postMessage(null);
+ </script>
+</span>
+
+<span>
+ <div>color-burn</div>
+ <canvas id="canvas16" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script id="myWorker16" type="text/worker">
+ self.onmessage = function(e) {
+ const canvas = new OffscreenCanvas(90, 90);
+ const ctx = canvas.getContext('2d');
+
+ 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 = 'color-burn';
+ 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();
+
+ const bitmap = canvas.transferToImageBitmap();
+ self.postMessage(bitmap, bitmap);
+ };
+ </script>
+ <script type="module">
+ const blob = new Blob([document.getElementById('myWorker16').textContent]);
+ const worker = new Worker(URL.createObjectURL(blob));
+ worker.addEventListener('message', msg => {
+ const outputCanvas = document.getElementById('canvas16');
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(msg.data, 0, 0);
+ if (--pending_tests == 0) {
+ document.documentElement.classList.remove('reftest-wait');
+ }
+ });
+ worker.postMessage(null);
+ </script>
+</span>
+
+<span>
+ <div>hard-light</div>
+ <canvas id="canvas17" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script id="myWorker17" type="text/worker">
+ self.onmessage = function(e) {
+ const canvas = new OffscreenCanvas(90, 90);
+ const ctx = canvas.getContext('2d');
+
+ 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 = 'hard-light';
+ 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();
+
+ const bitmap = canvas.transferToImageBitmap();
+ self.postMessage(bitmap, bitmap);
+ };
+ </script>
+ <script type="module">
+ const blob = new Blob([document.getElementById('myWorker17').textContent]);
+ const worker = new Worker(URL.createObjectURL(blob));
+ worker.addEventListener('message', msg => {
+ const outputCanvas = document.getElementById('canvas17');
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(msg.data, 0, 0);
+ if (--pending_tests == 0) {
+ document.documentElement.classList.remove('reftest-wait');
+ }
+ });
+ worker.postMessage(null);
+ </script>
+</span>
+
+<span>
+ <div>soft-light</div>
+ <canvas id="canvas18" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script id="myWorker18" type="text/worker">
+ self.onmessage = function(e) {
+ const canvas = new OffscreenCanvas(90, 90);
+ const ctx = canvas.getContext('2d');
+
+ 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 = 'soft-light';
+ 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();
+
+ const bitmap = canvas.transferToImageBitmap();
+ self.postMessage(bitmap, bitmap);
+ };
+ </script>
+ <script type="module">
+ const blob = new Blob([document.getElementById('myWorker18').textContent]);
+ const worker = new Worker(URL.createObjectURL(blob));
+ worker.addEventListener('message', msg => {
+ const outputCanvas = document.getElementById('canvas18');
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(msg.data, 0, 0);
+ if (--pending_tests == 0) {
+ document.documentElement.classList.remove('reftest-wait');
+ }
+ });
+ worker.postMessage(null);
+ </script>
+</span>
+
+<span>
+ <div>difference</div>
+ <canvas id="canvas19" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script id="myWorker19" type="text/worker">
+ self.onmessage = function(e) {
+ const canvas = new OffscreenCanvas(90, 90);
+ const ctx = canvas.getContext('2d');
+
+ 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 = 'difference';
+ 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();
+
+ const bitmap = canvas.transferToImageBitmap();
+ self.postMessage(bitmap, bitmap);
+ };
+ </script>
+ <script type="module">
+ const blob = new Blob([document.getElementById('myWorker19').textContent]);
+ const worker = new Worker(URL.createObjectURL(blob));
+ worker.addEventListener('message', msg => {
+ const outputCanvas = document.getElementById('canvas19');
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(msg.data, 0, 0);
+ if (--pending_tests == 0) {
+ document.documentElement.classList.remove('reftest-wait');
+ }
+ });
+ worker.postMessage(null);
+ </script>
+</span>
+
+<span>
+ <div>exclusion</div>
+ <canvas id="canvas20" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script id="myWorker20" type="text/worker">
+ self.onmessage = function(e) {
+ const canvas = new OffscreenCanvas(90, 90);
+ const ctx = canvas.getContext('2d');
+
+ 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 = 'exclusion';
+ 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();
+
+ const bitmap = canvas.transferToImageBitmap();
+ self.postMessage(bitmap, bitmap);
+ };
+ </script>
+ <script type="module">
+ const blob = new Blob([document.getElementById('myWorker20').textContent]);
+ const worker = new Worker(URL.createObjectURL(blob));
+ worker.addEventListener('message', msg => {
+ const outputCanvas = document.getElementById('canvas20');
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(msg.data, 0, 0);
+ if (--pending_tests == 0) {
+ document.documentElement.classList.remove('reftest-wait');
+ }
+ });
+ worker.postMessage(null);
+ </script>
+</span>
+
+<span>
+ <div>hue</div>
+ <canvas id="canvas21" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script id="myWorker21" type="text/worker">
+ self.onmessage = function(e) {
+ const canvas = new OffscreenCanvas(90, 90);
+ const ctx = canvas.getContext('2d');
+
+ 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 = 'hue';
+ 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();
+
+ const bitmap = canvas.transferToImageBitmap();
+ self.postMessage(bitmap, bitmap);
+ };
+ </script>
+ <script type="module">
+ const blob = new Blob([document.getElementById('myWorker21').textContent]);
+ const worker = new Worker(URL.createObjectURL(blob));
+ worker.addEventListener('message', msg => {
+ const outputCanvas = document.getElementById('canvas21');
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(msg.data, 0, 0);
+ if (--pending_tests == 0) {
+ document.documentElement.classList.remove('reftest-wait');
+ }
+ });
+ worker.postMessage(null);
+ </script>
+</span>
+
+<span>
+ <div>saturation</div>
+ <canvas id="canvas22" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script id="myWorker22" type="text/worker">
+ self.onmessage = function(e) {
+ const canvas = new OffscreenCanvas(90, 90);
+ const ctx = canvas.getContext('2d');
+
+ 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 = 'saturation';
+ 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();
+
+ const bitmap = canvas.transferToImageBitmap();
+ self.postMessage(bitmap, bitmap);
+ };
+ </script>
+ <script type="module">
+ const blob = new Blob([document.getElementById('myWorker22').textContent]);
+ const worker = new Worker(URL.createObjectURL(blob));
+ worker.addEventListener('message', msg => {
+ const outputCanvas = document.getElementById('canvas22');
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(msg.data, 0, 0);
+ if (--pending_tests == 0) {
+ document.documentElement.classList.remove('reftest-wait');
+ }
+ });
+ worker.postMessage(null);
+ </script>
+</span>
+
+<span>
+ <div>color</div>
+ <canvas id="canvas23" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script id="myWorker23" type="text/worker">
+ self.onmessage = function(e) {
+ const canvas = new OffscreenCanvas(90, 90);
+ const ctx = canvas.getContext('2d');
+
+ 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 = 'color';
+ 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();
+
+ const bitmap = canvas.transferToImageBitmap();
+ self.postMessage(bitmap, bitmap);
+ };
+ </script>
+ <script type="module">
+ const blob = new Blob([document.getElementById('myWorker23').textContent]);
+ const worker = new Worker(URL.createObjectURL(blob));
+ worker.addEventListener('message', msg => {
+ const outputCanvas = document.getElementById('canvas23');
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(msg.data, 0, 0);
+ if (--pending_tests == 0) {
+ document.documentElement.classList.remove('reftest-wait');
+ }
+ });
+ worker.postMessage(null);
+ </script>
+</span>
+
+<span>
+ <div>luminosity</div>
+ <canvas id="canvas24" width="90" height="90" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script id="myWorker24" type="text/worker">
+ self.onmessage = function(e) {
+ const canvas = new OffscreenCanvas(90, 90);
+ const ctx = canvas.getContext('2d');
+
+ 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 = 'luminosity';
+ 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();
+
+ const bitmap = canvas.transferToImageBitmap();
+ self.postMessage(bitmap, bitmap);
+ };
+ </script>
+ <script type="module">
+ const blob = new Blob([document.getElementById('myWorker24').textContent]);
+ const worker = new Worker(URL.createObjectURL(blob));
+ worker.addEventListener('message', msg => {
+ const outputCanvas = document.getElementById('canvas24');
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(msg.data, 0, 0);
+ if (--pending_tests == 0) {
+ document.documentElement.classList.remove('reftest-wait');
+ }
+ });
+ worker.postMessage(null);
+ </script>
+</span>
+
+</div>
+</html>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.invalid-calls.beginLayer-reset-endLayer.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.invalid-calls.beginLayer-reset-endLayer.html
index c0b11aa611..e588e48b5f 100644
--- a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.invalid-calls.beginLayer-reset-endLayer.html
+++ b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.invalid-calls.beginLayer-reset-endLayer.html
@@ -10,13 +10,7 @@
<script>
-var t = async_test("Raises exception on beginLayer() + reset() + endLayer().");
-var t_pass = t.done.bind(t);
-var t_fail = t.step_func(function(reason) {
- throw reason;
-});
-t.step(function() {
-
+test(t => {
var canvas = new OffscreenCanvas(100, 50);
var ctx = canvas.getContext('2d');
@@ -25,7 +19,6 @@ t.step(function() {
ctx.reset();
ctx.endLayer();
});
- t.done();
-});
+}, "Raises exception on beginLayer() + reset() + endLayer().");
</script>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.invalid-calls.beginLayer-reset-endLayer.worker.js b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.invalid-calls.beginLayer-reset-endLayer.worker.js
index 1c147d6f34..cab1b9d92d 100644
--- a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.invalid-calls.beginLayer-reset-endLayer.worker.js
+++ b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.invalid-calls.beginLayer-reset-endLayer.worker.js
@@ -6,13 +6,7 @@
importScripts("/resources/testharness.js");
importScripts("/html/canvas/resources/canvas-tests.js");
-var t = async_test("Raises exception on beginLayer() + reset() + endLayer().");
-var t_pass = t.done.bind(t);
-var t_fail = t.step_func(function(reason) {
- throw reason;
-});
-t.step(function() {
-
+test(t => {
var canvas = new OffscreenCanvas(100, 50);
var ctx = canvas.getContext('2d');
@@ -21,6 +15,5 @@ t.step(function() {
ctx.reset();
ctx.endLayer();
});
- t.done();
-});
+}, "Raises exception on beginLayer() + reset() + endLayer().");
done();
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.invalid-calls.beginLayer-restore.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.invalid-calls.beginLayer-restore.html
index 022532b329..30a981f75a 100644
--- a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.invalid-calls.beginLayer-restore.html
+++ b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.invalid-calls.beginLayer-restore.html
@@ -10,13 +10,7 @@
<script>
-var t = async_test("Raises exception on beginLayer() + restore().");
-var t_pass = t.done.bind(t);
-var t_fail = t.step_func(function(reason) {
- throw reason;
-});
-t.step(function() {
-
+test(t => {
var canvas = new OffscreenCanvas(100, 50);
var ctx = canvas.getContext('2d');
@@ -24,7 +18,6 @@ t.step(function() {
ctx.beginLayer();
ctx.restore();
});
- t.done();
-});
+}, "Raises exception on beginLayer() + restore().");
</script>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.invalid-calls.beginLayer-restore.worker.js b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.invalid-calls.beginLayer-restore.worker.js
index 1aa86635e6..287f8eb004 100644
--- a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.invalid-calls.beginLayer-restore.worker.js
+++ b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.invalid-calls.beginLayer-restore.worker.js
@@ -6,13 +6,7 @@
importScripts("/resources/testharness.js");
importScripts("/html/canvas/resources/canvas-tests.js");
-var t = async_test("Raises exception on beginLayer() + restore().");
-var t_pass = t.done.bind(t);
-var t_fail = t.step_func(function(reason) {
- throw reason;
-});
-t.step(function() {
-
+test(t => {
var canvas = new OffscreenCanvas(100, 50);
var ctx = canvas.getContext('2d');
@@ -20,6 +14,5 @@ t.step(function() {
ctx.beginLayer();
ctx.restore();
});
- t.done();
-});
+}, "Raises exception on beginLayer() + restore().");
done();
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.invalid-calls.beginLayer-save-endLayer.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.invalid-calls.beginLayer-save-endLayer.html
index 26dd0eee4b..04992b115e 100644
--- a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.invalid-calls.beginLayer-save-endLayer.html
+++ b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.invalid-calls.beginLayer-save-endLayer.html
@@ -10,13 +10,7 @@
<script>
-var t = async_test("Raises exception on beginLayer() + save() + endLayer().");
-var t_pass = t.done.bind(t);
-var t_fail = t.step_func(function(reason) {
- throw reason;
-});
-t.step(function() {
-
+test(t => {
var canvas = new OffscreenCanvas(100, 50);
var ctx = canvas.getContext('2d');
@@ -25,7 +19,6 @@ t.step(function() {
ctx.save();
ctx.endLayer();
});
- t.done();
-});
+}, "Raises exception on beginLayer() + save() + endLayer().");
</script>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.invalid-calls.beginLayer-save-endLayer.worker.js b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.invalid-calls.beginLayer-save-endLayer.worker.js
index 613921c67c..402bf5e0fd 100644
--- a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.invalid-calls.beginLayer-save-endLayer.worker.js
+++ b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.invalid-calls.beginLayer-save-endLayer.worker.js
@@ -6,13 +6,7 @@
importScripts("/resources/testharness.js");
importScripts("/html/canvas/resources/canvas-tests.js");
-var t = async_test("Raises exception on beginLayer() + save() + endLayer().");
-var t_pass = t.done.bind(t);
-var t_fail = t.step_func(function(reason) {
- throw reason;
-});
-t.step(function() {
-
+test(t => {
var canvas = new OffscreenCanvas(100, 50);
var ctx = canvas.getContext('2d');
@@ -21,6 +15,5 @@ t.step(function() {
ctx.save();
ctx.endLayer();
});
- t.done();
-});
+}, "Raises exception on beginLayer() + save() + endLayer().");
done();
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.invalid-calls.endLayer.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.invalid-calls.endLayer.html
index 440249980a..5b7f8a851e 100644
--- a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.invalid-calls.endLayer.html
+++ b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.invalid-calls.endLayer.html
@@ -10,20 +10,13 @@
<script>
-var t = async_test("Raises exception on lone endLayer calls.");
-var t_pass = t.done.bind(t);
-var t_fail = t.step_func(function(reason) {
- throw reason;
-});
-t.step(function() {
-
+test(t => {
var canvas = new OffscreenCanvas(100, 50);
var ctx = canvas.getContext('2d');
assert_throws_dom("INVALID_STATE_ERR", function() {
ctx.endLayer();
});
- t.done();
-});
+}, "Raises exception on lone endLayer calls.");
</script>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.invalid-calls.endLayer.worker.js b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.invalid-calls.endLayer.worker.js
index b2ba231b9c..2229aa9628 100644
--- a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.invalid-calls.endLayer.worker.js
+++ b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.invalid-calls.endLayer.worker.js
@@ -6,19 +6,12 @@
importScripts("/resources/testharness.js");
importScripts("/html/canvas/resources/canvas-tests.js");
-var t = async_test("Raises exception on lone endLayer calls.");
-var t_pass = t.done.bind(t);
-var t_fail = t.step_func(function(reason) {
- throw reason;
-});
-t.step(function() {
-
+test(t => {
var canvas = new OffscreenCanvas(100, 50);
var ctx = canvas.getContext('2d');
assert_throws_dom("INVALID_STATE_ERR", function() {
ctx.endLayer();
});
- t.done();
-});
+}, "Raises exception on lone endLayer calls.");
done();
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.invalid-calls.save-beginLayer-restore.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.invalid-calls.save-beginLayer-restore.html
index c2b09961ac..2a6c9b1ccb 100644
--- a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.invalid-calls.save-beginLayer-restore.html
+++ b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.invalid-calls.save-beginLayer-restore.html
@@ -10,13 +10,7 @@
<script>
-var t = async_test("Raises exception on save() + beginLayer() + restore().");
-var t_pass = t.done.bind(t);
-var t_fail = t.step_func(function(reason) {
- throw reason;
-});
-t.step(function() {
-
+test(t => {
var canvas = new OffscreenCanvas(100, 50);
var ctx = canvas.getContext('2d');
@@ -25,7 +19,6 @@ t.step(function() {
ctx.beginLayer();
ctx.restore();
});
- t.done();
-});
+}, "Raises exception on save() + beginLayer() + restore().");
</script>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.invalid-calls.save-beginLayer-restore.worker.js b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.invalid-calls.save-beginLayer-restore.worker.js
index d155379fcb..711280a6de 100644
--- a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.invalid-calls.save-beginLayer-restore.worker.js
+++ b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.invalid-calls.save-beginLayer-restore.worker.js
@@ -6,13 +6,7 @@
importScripts("/resources/testharness.js");
importScripts("/html/canvas/resources/canvas-tests.js");
-var t = async_test("Raises exception on save() + beginLayer() + restore().");
-var t_pass = t.done.bind(t);
-var t_fail = t.step_func(function(reason) {
- throw reason;
-});
-t.step(function() {
-
+test(t => {
var canvas = new OffscreenCanvas(100, 50);
var ctx = canvas.getContext('2d');
@@ -21,6 +15,5 @@ t.step(function() {
ctx.beginLayer();
ctx.restore();
});
- t.done();
-});
+}, "Raises exception on save() + beginLayer() + restore().");
done();
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.invalid-calls.save-endLayer.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.invalid-calls.save-endLayer.html
index 01b62d1e85..32ca134663 100644
--- a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.invalid-calls.save-endLayer.html
+++ b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.invalid-calls.save-endLayer.html
@@ -10,13 +10,7 @@
<script>
-var t = async_test("Raises exception on save() + endLayer().");
-var t_pass = t.done.bind(t);
-var t_fail = t.step_func(function(reason) {
- throw reason;
-});
-t.step(function() {
-
+test(t => {
var canvas = new OffscreenCanvas(100, 50);
var ctx = canvas.getContext('2d');
@@ -24,7 +18,6 @@ t.step(function() {
ctx.save();
ctx.endLayer();
});
- t.done();
-});
+}, "Raises exception on save() + endLayer().");
</script>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.invalid-calls.save-endLayer.worker.js b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.invalid-calls.save-endLayer.worker.js
index 353c1b00cd..af3667e50a 100644
--- a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.invalid-calls.save-endLayer.worker.js
+++ b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.invalid-calls.save-endLayer.worker.js
@@ -6,13 +6,7 @@
importScripts("/resources/testharness.js");
importScripts("/html/canvas/resources/canvas-tests.js");
-var t = async_test("Raises exception on save() + endLayer().");
-var t_pass = t.done.bind(t);
-var t_fail = t.step_func(function(reason) {
- throw reason;
-});
-t.step(function() {
-
+test(t => {
var canvas = new OffscreenCanvas(100, 50);
var ctx = canvas.getContext('2d');
@@ -20,6 +14,5 @@ t.step(function() {
ctx.save();
ctx.endLayer();
});
- t.done();
-});
+}, "Raises exception on save() + endLayer().");
done();
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.malformed-operations-with-promises.convertToBlob.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.malformed-operations-with-promises.convertToBlob.html
deleted file mode 100644
index 0b3854c31d..0000000000
--- a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.malformed-operations-with-promises.convertToBlob.html
+++ /dev/null
@@ -1,27 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<title>OffscreenCanvas test: 2d.layer.malformed-operations-with-promises.convertToBlob</title>
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-<script src="/html/canvas/resources/canvas-tests.js"></script>
-
-<h1>2d.layer.malformed-operations-with-promises.convertToBlob</h1>
-<p class="desc">Check that exceptions are thrown for operations that are malformed while layers are open.</p>
-
-
-<script>
-promise_test(async t => {
-
- var canvas = new OffscreenCanvas(200, 200);
- var ctx = canvas.getContext('2d');
-
- // Shouldn't throw on its own.
- await canvas.convertToBlob();
- // Make sure the exception isn't caused by calling the function twice.
- await canvas.convertToBlob();
- // Calling again inside a layer should throw.
- ctx.beginLayer();
- await promise_rejects_dom(t, 'InvalidStateError', canvas.convertToBlob());
-
-}, "Check that exceptions are thrown for operations that are malformed while layers are open.");
-</script>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.malformed-operations-with-promises.convertToBlob.worker.js b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.malformed-operations-with-promises.convertToBlob.worker.js
deleted file mode 100644
index 8361e19108..0000000000
--- a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.malformed-operations-with-promises.convertToBlob.worker.js
+++ /dev/null
@@ -1,21 +0,0 @@
-// DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py.
-// OffscreenCanvas test in a worker:2d.layer.malformed-operations-with-promises.convertToBlob
-// Description:Check that exceptions are thrown for operations that are malformed while layers are open.
-// Note:
-
-importScripts("/resources/testharness.js");
-importScripts("/html/canvas/resources/canvas-tests.js");
-
-promise_test(async t => {
- var canvas = new OffscreenCanvas(200, 200);
- var ctx = canvas.getContext('2d');
-
- // Shouldn't throw on its own.
- await canvas.convertToBlob();
- // Make sure the exception isn't caused by calling the function twice.
- await canvas.convertToBlob();
- // Calling again inside a layer should throw.
- ctx.beginLayer();
- await promise_rejects_dom(t, 'InvalidStateError', canvas.convertToBlob());
-}, "Check that exceptions are thrown for operations that are malformed while layers are open.");
-done();
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.malformed-operations-with-promises.createImageBitmap.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.malformed-operations-with-promises.createImageBitmap.html
deleted file mode 100644
index 085554d9f5..0000000000
--- a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.malformed-operations-with-promises.createImageBitmap.html
+++ /dev/null
@@ -1,27 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<title>OffscreenCanvas test: 2d.layer.malformed-operations-with-promises.createImageBitmap</title>
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-<script src="/html/canvas/resources/canvas-tests.js"></script>
-
-<h1>2d.layer.malformed-operations-with-promises.createImageBitmap</h1>
-<p class="desc">Check that exceptions are thrown for operations that are malformed while layers are open.</p>
-
-
-<script>
-promise_test(async t => {
-
- var canvas = new OffscreenCanvas(200, 200);
- var ctx = canvas.getContext('2d');
-
- // Shouldn't throw on its own.
- await createImageBitmap(canvas);
- // Make sure the exception isn't caused by calling the function twice.
- await createImageBitmap(canvas);
- // Calling again inside a layer should throw.
- ctx.beginLayer();
- await promise_rejects_dom(t, 'InvalidStateError', createImageBitmap(canvas));
-
-}, "Check that exceptions are thrown for operations that are malformed while layers are open.");
-</script>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.malformed-operations-with-promises.createImageBitmap.worker.js b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.malformed-operations-with-promises.createImageBitmap.worker.js
deleted file mode 100644
index d64f693864..0000000000
--- a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.malformed-operations-with-promises.createImageBitmap.worker.js
+++ /dev/null
@@ -1,21 +0,0 @@
-// DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py.
-// OffscreenCanvas test in a worker:2d.layer.malformed-operations-with-promises.createImageBitmap
-// Description:Check that exceptions are thrown for operations that are malformed while layers are open.
-// Note:
-
-importScripts("/resources/testharness.js");
-importScripts("/html/canvas/resources/canvas-tests.js");
-
-promise_test(async t => {
- var canvas = new OffscreenCanvas(200, 200);
- var ctx = canvas.getContext('2d');
-
- // Shouldn't throw on its own.
- await createImageBitmap(canvas);
- // Make sure the exception isn't caused by calling the function twice.
- await createImageBitmap(canvas);
- // Calling again inside a layer should throw.
- ctx.beginLayer();
- await promise_rejects_dom(t, 'InvalidStateError', createImageBitmap(canvas));
-}, "Check that exceptions are thrown for operations that are malformed while layers are open.");
-done();
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.malformed-operations-with-promises.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.malformed-operations-with-promises.html
new file mode 100644
index 0000000000..7b8f9b0943
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.malformed-operations-with-promises.html
@@ -0,0 +1,38 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<title>OffscreenCanvas test: 2d.layer.malformed-operations-with-promises</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/html/canvas/resources/canvas-tests.js"></script>
+
+<script>
+
+promise_test(async t => {
+ const canvas = new OffscreenCanvas(200, 200);
+ const ctx = canvas.getContext('2d');
+
+ // Shouldn't throw on its own.
+ await canvas.convertToBlob();
+ // Make sure the exception isn't caused by calling the function twice.
+ await canvas.convertToBlob();
+ // Calling again inside a layer should throw.
+ ctx.beginLayer();
+ await promise_rejects_dom(t, 'InvalidStateError',
+ canvas.convertToBlob());
+}, "Throws if convertToBlob is called while layers are open.");
+
+promise_test(async t => {
+ const canvas = new OffscreenCanvas(200, 200);
+ const ctx = canvas.getContext('2d');
+
+ // Shouldn't throw on its own.
+ await createImageBitmap(canvas);
+ // Make sure the exception isn't caused by calling the function twice.
+ await createImageBitmap(canvas);
+ // Calling again inside a layer should throw.
+ ctx.beginLayer();
+ await promise_rejects_dom(t, 'InvalidStateError',
+ createImageBitmap(canvas));
+}, "Throws if createImageBitmap is called while layers are open.");
+
+</script>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.malformed-operations-with-promises.worker.js b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.malformed-operations-with-promises.worker.js
new file mode 100644
index 0000000000..693901b648
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.malformed-operations-with-promises.worker.js
@@ -0,0 +1,37 @@
+// DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py.
+// OffscreenCanvas test in a worker:2d.layer.malformed-operations-with-promises
+// Description:
+// Note:
+
+importScripts("/resources/testharness.js");
+importScripts("/html/canvas/resources/canvas-tests.js");
+
+promise_test(async t => {
+ const canvas = new OffscreenCanvas(200, 200);
+ const ctx = canvas.getContext('2d');
+
+ // Shouldn't throw on its own.
+ await canvas.convertToBlob();
+ // Make sure the exception isn't caused by calling the function twice.
+ await canvas.convertToBlob();
+ // Calling again inside a layer should throw.
+ ctx.beginLayer();
+ await promise_rejects_dom(t, 'InvalidStateError',
+ canvas.convertToBlob());
+}, "Throws if convertToBlob is called while layers are open.");
+
+promise_test(async t => {
+ const canvas = new OffscreenCanvas(200, 200);
+ const ctx = canvas.getContext('2d');
+
+ // Shouldn't throw on its own.
+ await createImageBitmap(canvas);
+ // Make sure the exception isn't caused by calling the function twice.
+ await createImageBitmap(canvas);
+ // Calling again inside a layer should throw.
+ ctx.beginLayer();
+ await promise_rejects_dom(t, 'InvalidStateError',
+ createImageBitmap(canvas));
+}, "Throws if createImageBitmap is called while layers are open.");
+
+done();
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.malformed-operations.createPattern.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.malformed-operations.createPattern.html
deleted file mode 100644
index a206e64ceb..0000000000
--- a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.malformed-operations.createPattern.html
+++ /dev/null
@@ -1,34 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<title>OffscreenCanvas test: 2d.layer.malformed-operations.createPattern</title>
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-<script src="/html/canvas/resources/canvas-tests.js"></script>
-
-<h1>2d.layer.malformed-operations.createPattern</h1>
-<p class="desc">Check that exceptions are thrown for operations that are malformed while layers are open.</p>
-
-
-<script>
-var t = async_test("Check that exceptions are thrown for operations that are malformed while layers are open.");
-var t_pass = t.done.bind(t);
-var t_fail = t.step_func(function(reason) {
- throw reason;
-});
-t.step(function() {
-
- var canvas = new OffscreenCanvas(200, 200);
- var ctx = canvas.getContext('2d');
-
- // Shouldn't throw on its own.
- ctx.createPattern(canvas, 'repeat');
- // Make sure the exception isn't caused by calling the function twice.
- ctx.createPattern(canvas, 'repeat');
- // Calling again inside a layer should throw.
- ctx.beginLayer();
- assert_throws_dom("InvalidStateError",
- () => ctx.createPattern(canvas, 'repeat'));
- t.done();
-
-});
-</script>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.malformed-operations.createPattern.worker.js b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.malformed-operations.createPattern.worker.js
deleted file mode 100644
index bcb42cba87..0000000000
--- a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.malformed-operations.createPattern.worker.js
+++ /dev/null
@@ -1,29 +0,0 @@
-// DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py.
-// OffscreenCanvas test in a worker:2d.layer.malformed-operations.createPattern
-// Description:Check that exceptions are thrown for operations that are malformed while layers are open.
-// Note:
-
-importScripts("/resources/testharness.js");
-importScripts("/html/canvas/resources/canvas-tests.js");
-
-var t = async_test("Check that exceptions are thrown for operations that are malformed while layers are open.");
-var t_pass = t.done.bind(t);
-var t_fail = t.step_func(function(reason) {
- throw reason;
-});
-t.step(function() {
-
- var canvas = new OffscreenCanvas(200, 200);
- var ctx = canvas.getContext('2d');
-
- // Shouldn't throw on its own.
- ctx.createPattern(canvas, 'repeat');
- // Make sure the exception isn't caused by calling the function twice.
- ctx.createPattern(canvas, 'repeat');
- // Calling again inside a layer should throw.
- ctx.beginLayer();
- assert_throws_dom("InvalidStateError",
- () => ctx.createPattern(canvas, 'repeat'));
- t.done();
-});
-done();
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.malformed-operations.drawImage.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.malformed-operations.drawImage.html
deleted file mode 100644
index e6a9872100..0000000000
--- a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.malformed-operations.drawImage.html
+++ /dev/null
@@ -1,36 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<title>OffscreenCanvas test: 2d.layer.malformed-operations.drawImage</title>
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-<script src="/html/canvas/resources/canvas-tests.js"></script>
-
-<h1>2d.layer.malformed-operations.drawImage</h1>
-<p class="desc">Check that exceptions are thrown for operations that are malformed while layers are open.</p>
-
-
-<script>
-var t = async_test("Check that exceptions are thrown for operations that are malformed while layers are open.");
-var t_pass = t.done.bind(t);
-var t_fail = t.step_func(function(reason) {
- throw reason;
-});
-t.step(function() {
-
- var canvas = new OffscreenCanvas(200, 200);
- var ctx = canvas.getContext('2d');
-
- const canvas2 = new OffscreenCanvas(200, 200);
- const ctx2 = canvas2.getContext('2d');
- // Shouldn't throw on its own.
- ctx2.drawImage(canvas, 0, 0);
- // Make sure the exception isn't caused by calling the function twice.
- ctx2.drawImage(canvas, 0, 0);
- // Calling again inside a layer should throw.
- ctx.beginLayer();
- assert_throws_dom("InvalidStateError",
- () => ctx2.drawImage(canvas, 0, 0));
- t.done();
-
-});
-</script>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.malformed-operations.drawImage.worker.js b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.malformed-operations.drawImage.worker.js
deleted file mode 100644
index b66cdee62e..0000000000
--- a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.malformed-operations.drawImage.worker.js
+++ /dev/null
@@ -1,31 +0,0 @@
-// DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py.
-// OffscreenCanvas test in a worker:2d.layer.malformed-operations.drawImage
-// Description:Check that exceptions are thrown for operations that are malformed while layers are open.
-// Note:
-
-importScripts("/resources/testharness.js");
-importScripts("/html/canvas/resources/canvas-tests.js");
-
-var t = async_test("Check that exceptions are thrown for operations that are malformed while layers are open.");
-var t_pass = t.done.bind(t);
-var t_fail = t.step_func(function(reason) {
- throw reason;
-});
-t.step(function() {
-
- var canvas = new OffscreenCanvas(200, 200);
- var ctx = canvas.getContext('2d');
-
- const canvas2 = new OffscreenCanvas(200, 200);
- const ctx2 = canvas2.getContext('2d');
- // Shouldn't throw on its own.
- ctx2.drawImage(canvas, 0, 0);
- // Make sure the exception isn't caused by calling the function twice.
- ctx2.drawImage(canvas, 0, 0);
- // Calling again inside a layer should throw.
- ctx.beginLayer();
- assert_throws_dom("InvalidStateError",
- () => ctx2.drawImage(canvas, 0, 0));
- t.done();
-});
-done();
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.malformed-operations.getImageData.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.malformed-operations.getImageData.html
deleted file mode 100644
index 87bc8c6ede..0000000000
--- a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.malformed-operations.getImageData.html
+++ /dev/null
@@ -1,34 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<title>OffscreenCanvas test: 2d.layer.malformed-operations.getImageData</title>
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-<script src="/html/canvas/resources/canvas-tests.js"></script>
-
-<h1>2d.layer.malformed-operations.getImageData</h1>
-<p class="desc">Check that exceptions are thrown for operations that are malformed while layers are open.</p>
-
-
-<script>
-var t = async_test("Check that exceptions are thrown for operations that are malformed while layers are open.");
-var t_pass = t.done.bind(t);
-var t_fail = t.step_func(function(reason) {
- throw reason;
-});
-t.step(function() {
-
- var canvas = new OffscreenCanvas(200, 200);
- var ctx = canvas.getContext('2d');
-
- // Shouldn't throw on its own.
- ctx.getImageData(0, 0, 200, 200);
- // Make sure the exception isn't caused by calling the function twice.
- ctx.getImageData(0, 0, 200, 200);
- // Calling again inside a layer should throw.
- ctx.beginLayer();
- assert_throws_dom("InvalidStateError",
- () => ctx.getImageData(0, 0, 200, 200));
- t.done();
-
-});
-</script>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.malformed-operations.getImageData.worker.js b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.malformed-operations.getImageData.worker.js
deleted file mode 100644
index 6a1a16fccb..0000000000
--- a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.malformed-operations.getImageData.worker.js
+++ /dev/null
@@ -1,29 +0,0 @@
-// DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py.
-// OffscreenCanvas test in a worker:2d.layer.malformed-operations.getImageData
-// Description:Check that exceptions are thrown for operations that are malformed while layers are open.
-// Note:
-
-importScripts("/resources/testharness.js");
-importScripts("/html/canvas/resources/canvas-tests.js");
-
-var t = async_test("Check that exceptions are thrown for operations that are malformed while layers are open.");
-var t_pass = t.done.bind(t);
-var t_fail = t.step_func(function(reason) {
- throw reason;
-});
-t.step(function() {
-
- var canvas = new OffscreenCanvas(200, 200);
- var ctx = canvas.getContext('2d');
-
- // Shouldn't throw on its own.
- ctx.getImageData(0, 0, 200, 200);
- // Make sure the exception isn't caused by calling the function twice.
- ctx.getImageData(0, 0, 200, 200);
- // Calling again inside a layer should throw.
- ctx.beginLayer();
- assert_throws_dom("InvalidStateError",
- () => ctx.getImageData(0, 0, 200, 200));
- t.done();
-});
-done();
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.malformed-operations.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.malformed-operations.html
new file mode 100644
index 0000000000..a810665faf
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.malformed-operations.html
@@ -0,0 +1,85 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<title>OffscreenCanvas test: 2d.layer.malformed-operations</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/html/canvas/resources/canvas-tests.js"></script>
+
+<script>
+
+test(t => {
+ const canvas = new OffscreenCanvas(200, 200);
+ const ctx = canvas.getContext('2d');
+
+ // Shouldn't throw on its own.
+ ctx.createPattern(canvas, 'repeat');
+ // Make sure the exception isn't caused by calling the function twice.
+ ctx.createPattern(canvas, 'repeat');
+ // Calling again inside a layer should throw.
+ ctx.beginLayer();
+ assert_throws_dom("InvalidStateError",
+ () => ctx.createPattern(canvas, 'repeat'));
+}, "Throws if createPattern is called while layers are open.");
+
+test(t => {
+ const canvas = new OffscreenCanvas(200, 200);
+ const ctx = canvas.getContext('2d');
+
+ const canvas2 = new OffscreenCanvas(200, 200);
+ const ctx2 = canvas2.getContext('2d');
+ // Shouldn't throw on its own.
+ ctx2.drawImage(canvas, 0, 0);
+ // Make sure the exception isn't caused by calling the function twice.
+ ctx2.drawImage(canvas, 0, 0);
+ // Calling again inside a layer should throw.
+ ctx.beginLayer();
+ assert_throws_dom("InvalidStateError",
+ () => ctx2.drawImage(canvas, 0, 0));
+}, "Throws if drawImage is called while layers are open.");
+
+test(t => {
+ const canvas = new OffscreenCanvas(200, 200);
+ const ctx = canvas.getContext('2d');
+
+ // Shouldn't throw on its own.
+ ctx.getImageData(0, 0, 200, 200);
+ // Make sure the exception isn't caused by calling the function twice.
+ ctx.getImageData(0, 0, 200, 200);
+ // Calling again inside a layer should throw.
+ ctx.beginLayer();
+ assert_throws_dom("InvalidStateError",
+ () => ctx.getImageData(0, 0, 200, 200));
+}, "Throws if getImageData is called while layers are open.");
+
+test(t => {
+ const canvas = new OffscreenCanvas(200, 200);
+ const ctx = canvas.getContext('2d');
+
+ const canvas2 = new OffscreenCanvas(200, 200);
+ const ctx2 = canvas2.getContext('2d')
+ const data = ctx2.getImageData(0, 0, 1, 1);
+ // Shouldn't throw on its own.
+ ctx.putImageData(data, 0, 0);
+ // Make sure the exception isn't caused by calling the function twice.
+ ctx.putImageData(data, 0, 0);
+ // Calling again inside a layer should throw.
+ ctx.beginLayer();
+ assert_throws_dom("InvalidStateError",
+ () => ctx.putImageData(data, 0, 0));
+}, "Throws if putImageData is called while layers are open.");
+
+test(t => {
+ const canvas = new OffscreenCanvas(200, 200);
+ const ctx = canvas.getContext('2d');
+
+ // Shouldn't throw on its own.
+ canvas.transferToImageBitmap();
+ // Make sure the exception isn't caused by calling the function twice.
+ canvas.transferToImageBitmap();
+ // Calling again inside a layer should throw.
+ ctx.beginLayer();
+ assert_throws_dom("InvalidStateError",
+ () => canvas.transferToImageBitmap());
+}, "Throws if transferToImageBitmap is called while layers are open.");
+
+</script>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.malformed-operations.putImageData.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.malformed-operations.putImageData.html
deleted file mode 100644
index e8059076bb..0000000000
--- a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.malformed-operations.putImageData.html
+++ /dev/null
@@ -1,37 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<title>OffscreenCanvas test: 2d.layer.malformed-operations.putImageData</title>
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-<script src="/html/canvas/resources/canvas-tests.js"></script>
-
-<h1>2d.layer.malformed-operations.putImageData</h1>
-<p class="desc">Check that exceptions are thrown for operations that are malformed while layers are open.</p>
-
-
-<script>
-var t = async_test("Check that exceptions are thrown for operations that are malformed while layers are open.");
-var t_pass = t.done.bind(t);
-var t_fail = t.step_func(function(reason) {
- throw reason;
-});
-t.step(function() {
-
- var canvas = new OffscreenCanvas(200, 200);
- var ctx = canvas.getContext('2d');
-
- const canvas2 = new OffscreenCanvas(200, 200);
- const ctx2 = canvas2.getContext('2d')
- const data = ctx2.getImageData(0, 0, 1, 1);
- // Shouldn't throw on its own.
- ctx.putImageData(data, 0, 0);
- // Make sure the exception isn't caused by calling the function twice.
- ctx.putImageData(data, 0, 0);
- // Calling again inside a layer should throw.
- ctx.beginLayer();
- assert_throws_dom("InvalidStateError",
- () => ctx.putImageData(data, 0, 0));
- t.done();
-
-});
-</script>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.malformed-operations.putImageData.worker.js b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.malformed-operations.putImageData.worker.js
deleted file mode 100644
index 8810c3a73c..0000000000
--- a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.malformed-operations.putImageData.worker.js
+++ /dev/null
@@ -1,32 +0,0 @@
-// DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py.
-// OffscreenCanvas test in a worker:2d.layer.malformed-operations.putImageData
-// Description:Check that exceptions are thrown for operations that are malformed while layers are open.
-// Note:
-
-importScripts("/resources/testharness.js");
-importScripts("/html/canvas/resources/canvas-tests.js");
-
-var t = async_test("Check that exceptions are thrown for operations that are malformed while layers are open.");
-var t_pass = t.done.bind(t);
-var t_fail = t.step_func(function(reason) {
- throw reason;
-});
-t.step(function() {
-
- var canvas = new OffscreenCanvas(200, 200);
- var ctx = canvas.getContext('2d');
-
- const canvas2 = new OffscreenCanvas(200, 200);
- const ctx2 = canvas2.getContext('2d')
- const data = ctx2.getImageData(0, 0, 1, 1);
- // Shouldn't throw on its own.
- ctx.putImageData(data, 0, 0);
- // Make sure the exception isn't caused by calling the function twice.
- ctx.putImageData(data, 0, 0);
- // Calling again inside a layer should throw.
- ctx.beginLayer();
- assert_throws_dom("InvalidStateError",
- () => ctx.putImageData(data, 0, 0));
- t.done();
-});
-done();
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.malformed-operations.transferToImageBitmap.html b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.malformed-operations.transferToImageBitmap.html
deleted file mode 100644
index 79c216421f..0000000000
--- a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.malformed-operations.transferToImageBitmap.html
+++ /dev/null
@@ -1,34 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<title>OffscreenCanvas test: 2d.layer.malformed-operations.transferToImageBitmap</title>
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-<script src="/html/canvas/resources/canvas-tests.js"></script>
-
-<h1>2d.layer.malformed-operations.transferToImageBitmap</h1>
-<p class="desc">Check that exceptions are thrown for operations that are malformed while layers are open.</p>
-
-
-<script>
-var t = async_test("Check that exceptions are thrown for operations that are malformed while layers are open.");
-var t_pass = t.done.bind(t);
-var t_fail = t.step_func(function(reason) {
- throw reason;
-});
-t.step(function() {
-
- var canvas = new OffscreenCanvas(200, 200);
- var ctx = canvas.getContext('2d');
-
- // Shouldn't throw on its own.
- canvas.transferToImageBitmap();
- // Make sure the exception isn't caused by calling the function twice.
- canvas.transferToImageBitmap();
- // Calling again inside a layer should throw.
- ctx.beginLayer();
- assert_throws_dom("InvalidStateError",
- () => canvas.transferToImageBitmap());
- t.done();
-
-});
-</script>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.malformed-operations.transferToImageBitmap.worker.js b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.malformed-operations.transferToImageBitmap.worker.js
deleted file mode 100644
index be0b43665a..0000000000
--- a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.malformed-operations.transferToImageBitmap.worker.js
+++ /dev/null
@@ -1,29 +0,0 @@
-// DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py.
-// OffscreenCanvas test in a worker:2d.layer.malformed-operations.transferToImageBitmap
-// Description:Check that exceptions are thrown for operations that are malformed while layers are open.
-// Note:
-
-importScripts("/resources/testharness.js");
-importScripts("/html/canvas/resources/canvas-tests.js");
-
-var t = async_test("Check that exceptions are thrown for operations that are malformed while layers are open.");
-var t_pass = t.done.bind(t);
-var t_fail = t.step_func(function(reason) {
- throw reason;
-});
-t.step(function() {
-
- var canvas = new OffscreenCanvas(200, 200);
- var ctx = canvas.getContext('2d');
-
- // Shouldn't throw on its own.
- canvas.transferToImageBitmap();
- // Make sure the exception isn't caused by calling the function twice.
- canvas.transferToImageBitmap();
- // Calling again inside a layer should throw.
- ctx.beginLayer();
- assert_throws_dom("InvalidStateError",
- () => canvas.transferToImageBitmap());
- t.done();
-});
-done();
diff --git a/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.malformed-operations.worker.js b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.malformed-operations.worker.js
new file mode 100644
index 0000000000..5851fcfbc6
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/offscreen/layers/2d.layer.malformed-operations.worker.js
@@ -0,0 +1,84 @@
+// DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py.
+// OffscreenCanvas test in a worker:2d.layer.malformed-operations
+// Description:
+// Note:
+
+importScripts("/resources/testharness.js");
+importScripts("/html/canvas/resources/canvas-tests.js");
+
+test(t => {
+ const canvas = new OffscreenCanvas(200, 200);
+ const ctx = canvas.getContext('2d');
+
+ // Shouldn't throw on its own.
+ ctx.createPattern(canvas, 'repeat');
+ // Make sure the exception isn't caused by calling the function twice.
+ ctx.createPattern(canvas, 'repeat');
+ // Calling again inside a layer should throw.
+ ctx.beginLayer();
+ assert_throws_dom("InvalidStateError",
+ () => ctx.createPattern(canvas, 'repeat'));
+}, "Throws if createPattern is called while layers are open.");
+
+test(t => {
+ const canvas = new OffscreenCanvas(200, 200);
+ const ctx = canvas.getContext('2d');
+
+ const canvas2 = new OffscreenCanvas(200, 200);
+ const ctx2 = canvas2.getContext('2d');
+ // Shouldn't throw on its own.
+ ctx2.drawImage(canvas, 0, 0);
+ // Make sure the exception isn't caused by calling the function twice.
+ ctx2.drawImage(canvas, 0, 0);
+ // Calling again inside a layer should throw.
+ ctx.beginLayer();
+ assert_throws_dom("InvalidStateError",
+ () => ctx2.drawImage(canvas, 0, 0));
+}, "Throws if drawImage is called while layers are open.");
+
+test(t => {
+ const canvas = new OffscreenCanvas(200, 200);
+ const ctx = canvas.getContext('2d');
+
+ // Shouldn't throw on its own.
+ ctx.getImageData(0, 0, 200, 200);
+ // Make sure the exception isn't caused by calling the function twice.
+ ctx.getImageData(0, 0, 200, 200);
+ // Calling again inside a layer should throw.
+ ctx.beginLayer();
+ assert_throws_dom("InvalidStateError",
+ () => ctx.getImageData(0, 0, 200, 200));
+}, "Throws if getImageData is called while layers are open.");
+
+test(t => {
+ const canvas = new OffscreenCanvas(200, 200);
+ const ctx = canvas.getContext('2d');
+
+ const canvas2 = new OffscreenCanvas(200, 200);
+ const ctx2 = canvas2.getContext('2d')
+ const data = ctx2.getImageData(0, 0, 1, 1);
+ // Shouldn't throw on its own.
+ ctx.putImageData(data, 0, 0);
+ // Make sure the exception isn't caused by calling the function twice.
+ ctx.putImageData(data, 0, 0);
+ // Calling again inside a layer should throw.
+ ctx.beginLayer();
+ assert_throws_dom("InvalidStateError",
+ () => ctx.putImageData(data, 0, 0));
+}, "Throws if putImageData is called while layers are open.");
+
+test(t => {
+ const canvas = new OffscreenCanvas(200, 200);
+ const ctx = canvas.getContext('2d');
+
+ // Shouldn't throw on its own.
+ canvas.transferToImageBitmap();
+ // Make sure the exception isn't caused by calling the function twice.
+ canvas.transferToImageBitmap();
+ // Calling again inside a layer should throw.
+ ctx.beginLayer();
+ assert_throws_dom("InvalidStateError",
+ () => canvas.transferToImageBitmap());
+}, "Throws if transferToImageBitmap is called while layers are open.");
+
+done();
diff --git a/testing/web-platform/tests/html/canvas/offscreen/text/WEB_FEATURES.yml b/testing/web-platform/tests/html/canvas/offscreen/text/WEB_FEATURES.yml
new file mode 100644
index 0000000000..1d9e4bab82
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/offscreen/text/WEB_FEATURES.yml
@@ -0,0 +1,4 @@
+features:
+- name: canvas-text-baselines
+ files:
+ - 2d.text.measure.baselines.*
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
diff --git a/testing/web-platform/tests/html/cross-origin-embedder-policy/META.yml b/testing/web-platform/tests/html/cross-origin-embedder-policy/META.yml
index dc7010880b..066fcc2081 100644
--- a/testing/web-platform/tests/html/cross-origin-embedder-policy/META.yml
+++ b/testing/web-platform/tests/html/cross-origin-embedder-policy/META.yml
@@ -1,7 +1,6 @@
spec: https://html.spec.whatwg.org/multipage/origin.html#coep
suggested_reviewers:
- mikewest
- - jugglinmike
- arturjanc
- lweichselbaum
- hemeryar
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/META.yml b/testing/web-platform/tests/html/cross-origin-opener-policy/META.yml
index b9d578d22f..69c67da459 100644
--- a/testing/web-platform/tests/html/cross-origin-opener-policy/META.yml
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/META.yml
@@ -1,7 +1,6 @@
spec: https://html.spec.whatwg.org/multipage/origin.html#cross-origin-opener-policies
suggested_reviewers:
- mikewest
- - jugglinmike
- arturjanc
- lweichselbaum
- hemeryar
diff --git a/testing/web-platform/tests/html/dom/WEB_FEATURES.yml b/testing/web-platform/tests/html/dom/WEB_FEATURES.yml
new file mode 100644
index 0000000000..5c9e27d297
--- /dev/null
+++ b/testing/web-platform/tests/html/dom/WEB_FEATURES.yml
@@ -0,0 +1,4 @@
+features:
+- name: aria-attribute-reflection
+ files:
+ - aria-attribute-reflection.html
diff --git a/testing/web-platform/tests/html/dom/aria-element-reflection.html b/testing/web-platform/tests/html/dom/aria-element-reflection.html
index bdf2450708..e04610171b 100644
--- a/testing/web-platform/tests/html/dom/aria-element-reflection.html
+++ b/testing/web-platform/tests/html/dom/aria-element-reflection.html
@@ -611,7 +611,7 @@
</script>
<div id="sameScopeContainer">
- <div id="labeledby" aria-labeledby="headingLabel1 headingLabel2">Misspelling</div>
+ <div id="labelledby" aria-labelledby="headingLabel1 headingLabel2">Misspelling</div>
<div id="headingLabel1">Wonderful</div>
<div id="headingLabel2">Fantastic</div>
@@ -626,7 +626,7 @@
const headingLabel2 = document.getElementById("headingLabel2")
shadowRoot.appendChild(headingElement);
- assert_array_equals(labeledby.ariaLabelledByElements, [headingLabel1, headingLabel2], "aria-labeled by is supported by IDL getter.");
+ assert_array_equals(labelledby.ariaLabelledByElements, [headingLabel1, headingLabel2], "aria-labelledby is supported by IDL getter.");
// Explicitly set elements are in a lighter shadow DOM, so that's ok.
headingElement.ariaLabelledByElements = [headingLabel1, headingLabel2];
diff --git a/testing/web-platform/tests/html/dom/elements/global-attributes/the-anchor-attribute-003.tentative.html b/testing/web-platform/tests/html/dom/elements/global-attributes/the-anchor-attribute-003.tentative.html
index ec2d8d5ead..e8c12c784f 100644
--- a/testing/web-platform/tests/html/dom/elements/global-attributes/the-anchor-attribute-003.tentative.html
+++ b/testing/web-platform/tests/html/dom/elements/global-attributes/the-anchor-attribute-003.tentative.html
@@ -37,8 +37,8 @@ body {
dialog::backdrop {
top: calc(anchor(top) - 10px);
right: calc(anchor(right) - 10px);
- bottom: calc(anchor(bottom) - 10px);
- left: calc(anchor(left) - 10px);
+ bottom: calc(anchor(bottom, 0px) - 10px);
+ left: calc(anchor(left, 0px) - 10px);
background: lime;
}
diff --git a/testing/web-platform/tests/html/dom/elements/global-attributes/the-anchor-attribute-xml.tentative.html b/testing/web-platform/tests/html/dom/elements/global-attributes/the-anchor-attribute-xml.tentative.html
new file mode 100644
index 0000000000..c5e6d81826
--- /dev/null
+++ b/testing/web-platform/tests/html/dom/elements/global-attributes/the-anchor-attribute-xml.tentative.html
@@ -0,0 +1,25 @@
+<!DOCTYPE html>
+<link rel=author href="mailto:jarhar@chromium.org">
+<link rel="help" href="https://github.com/whatwg/html/pull/9144">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<body>
+<script>
+test(() => {
+ const xmlDoc = document.implementation.createDocument(null, 'root', null);
+ assert_equals(xmlDoc.contentType, 'application/xml');
+ xmlDoc.documentElement.innerHTML = '<div id="target">target</div><div anchor="target">anchored</div>';
+ assert_equals(xmlDoc.documentElement.innerHTML,
+ '<div id="target">target</div><div anchor="target">anchored</div>');
+ const target = xmlDoc.documentElement.children[0];
+ const anchored = xmlDoc.documentElement.children[1];
+
+ assert_equals(xmlDoc.documentElement.children[1].anchorElement, null,
+ 'Setting the anchor attribute in XML should not set the anchorElement IDL.');
+
+ anchored.anchorElement = target;
+ assert_equals(xmlDoc.documentElement.children[1].anchorElement, null,
+ 'Setting element.anchorElement in an XML document should not set the anchorElement IDL.');
+});
+</script>
diff --git a/testing/web-platform/tests/html/dom/render-blocking/WEB_FEATURES.yml b/testing/web-platform/tests/html/dom/render-blocking/WEB_FEATURES.yml
new file mode 100644
index 0000000000..36ab4f3010
--- /dev/null
+++ b/testing/web-platform/tests/html/dom/render-blocking/WEB_FEATURES.yml
@@ -0,0 +1,3 @@
+features:
+- name: blocking-render
+ files: "**"
diff --git a/testing/web-platform/tests/html/dom/usvstring-reflection.https.html b/testing/web-platform/tests/html/dom/usvstring-reflection.https.html
index 775cb49281..d8d830dc59 100644
--- a/testing/web-platform/tests/html/dom/usvstring-reflection.https.html
+++ b/testing/web-platform/tests/html/dom/usvstring-reflection.https.html
@@ -124,7 +124,7 @@ promise_test(t => {
const sendString = 'hello\uD999';
const receiveString = 'hello\uFFFD';
- return createDataChannelPair(t)
+ return createDataChannelPair(t, {})
.then(([channel1, channel2]) => {
channel1.send(sendString);
return awaitMessage(channel2)
diff --git a/testing/web-platform/tests/html/editing/dnd/events/drag-event-div-manual.html b/testing/web-platform/tests/html/editing/dnd/events/drag-event-div-manual.html
index 79c0c4332d..505b0049be 100644
--- a/testing/web-platform/tests/html/editing/dnd/events/drag-event-div-manual.html
+++ b/testing/web-platform/tests/html/editing/dnd/events/drag-event-div-manual.html
@@ -6,7 +6,6 @@
<link rel="author" title="Microsoft" href="http://www.microsoft.com/"/>
<link rel="help" href="http://dev.w3.org/html5/spec/dnd.html#drag-and-drop-processing-model"/>
<meta name="assert" content="Fire drag event when dragging a div element"/>
- <script src="../resources/dragdrop_support.js" type="text/javascript"></script>
<script type="text/javascript">
var EVENT, TARGET;
@@ -14,11 +13,11 @@
{
if ((TARGET == evt.target) && (EVENT == evt.type))
{
- LogTestResult("PASS");
+ document.getElementById("test_result").firstChild.data = "PASS";
}
else
{
- LogTestResult("FAIL");
+ document.getElementById("test_result").firstChild.data = "FAIL";
}
}
@@ -27,7 +26,7 @@
window.onload = function()
{
TARGET = document.getElementById("target");
- AddEventListenersForElement(EVENT, DragEvent, false, TARGET);
+ TARGET.addEventListener(EVENT, DragEvent, false);
}
</script>
</head>
diff --git a/testing/web-platform/tests/html/editing/dnd/events/drag-event-manual.html b/testing/web-platform/tests/html/editing/dnd/events/drag-event-manual.html
index d278b864bb..d3f517ea1d 100644
--- a/testing/web-platform/tests/html/editing/dnd/events/drag-event-manual.html
+++ b/testing/web-platform/tests/html/editing/dnd/events/drag-event-manual.html
@@ -6,7 +6,6 @@
<link rel="author" title="Microsoft" href="http://www.microsoft.com/"/>
<link rel="help" href="http://dev.w3.org/html5/spec/dnd.html#drag-and-drop-processing-model"/>
<meta name="assert" content="Fire drag event during the drag and drop processing"/>
- <script src="../resources/dragdrop_support.js" type="text/javascript"></script>
<script type="text/javascript">
var EVENT, TARGET;
@@ -14,11 +13,11 @@
{
if ((TARGET == evt.target) && (EVENT == evt.type))
{
- LogTestResult("PASS");
+ document.getElementById("test_result").firstChild.data = "PASS";
}
else
{
- LogTestResult("FAIL");
+ document.getElementById("test_result").firstChild.data = "FAIL";
}
}
@@ -27,7 +26,7 @@
window.onload = function()
{
TARGET = document.getElementById("target");
- AddEventListenersForElement(EVENT, DragEvent, false, TARGET);
+ TARGET.addEventListener(EVENT, DragEvent, false);
}
</script>
</head>
diff --git a/testing/web-platform/tests/html/editing/dnd/events/dragend-event-manual.html b/testing/web-platform/tests/html/editing/dnd/events/dragend-event-manual.html
index 8bfb1fb7b6..b4bb621e88 100644
--- a/testing/web-platform/tests/html/editing/dnd/events/dragend-event-manual.html
+++ b/testing/web-platform/tests/html/editing/dnd/events/dragend-event-manual.html
@@ -6,7 +6,6 @@
<link rel="author" title="Microsoft" href="http://www.microsoft.com/"/>
<link rel="help" href="http://dev.w3.org/html5/spec/dnd.html#drag-and-drop-processing-model"/>
<meta name="assert" content="Fire dragend event during the drag and drop processing"/>
- <script src="../resources/dragdrop_support.js" type="text/javascript"></script>
<script type="text/javascript">
var EVENT, TARGET;
@@ -14,11 +13,11 @@
{
if ((TARGET == evt.target) && (EVENT == evt.type))
{
- LogTestResult("PASS");
+ document.getElementById("test_result").firstChild.data = "PASS";
}
else
{
- LogTestResult("FAIL");
+ document.getElementById("test_result").firstChild.data = "FAIL";
}
}
@@ -27,7 +26,7 @@
window.onload = function()
{
TARGET = document.getElementById("target");
- AddEventListenersForElement(EVENT, DragendEvent, false, TARGET);
+ TARGET.addEventListener(EVENT, DragendEvent, false);
}
</script>
</head>
diff --git a/testing/web-platform/tests/html/editing/dnd/events/dragenter-event-manual.html b/testing/web-platform/tests/html/editing/dnd/events/dragenter-event-manual.html
index e81b32949c..23b404b0b1 100644
--- a/testing/web-platform/tests/html/editing/dnd/events/dragenter-event-manual.html
+++ b/testing/web-platform/tests/html/editing/dnd/events/dragenter-event-manual.html
@@ -6,7 +6,6 @@
<link rel="author" title="Microsoft" href="http://www.microsoft.com/"/>
<link rel="help" href="http://dev.w3.org/html5/spec/dnd.html#drag-and-drop-processing-model"/>
<meta name="assert" content="Fire dragenter event during the drag and drop processing"/>
- <script src="../resources/dragdrop_support.js" type="text/javascript"></script>
<script type="text/javascript">
var EVENT, TARGET;
@@ -14,11 +13,11 @@
{
if ((TARGET == evt.target) && (EVENT == evt.type))
{
- LogTestResult("PASS");
+ document.getElementById("test_result").firstChild.data = "PASS";
}
else
{
- LogTestResult("FAIL");
+ document.getElementById("test_result").firstChild.data = "FAIL";
}
}
@@ -27,7 +26,7 @@
window.onload = function()
{
TARGET = document.getElementById("target");
- AddEventListenersForElement(EVENT, DragenterEvent, false, TARGET);
+ TARGET.addEventListener(EVENT, DragenterEvent, false);
}
</script>
</head>
diff --git a/testing/web-platform/tests/html/editing/dnd/events/dragleave-event-manual.html b/testing/web-platform/tests/html/editing/dnd/events/dragleave-event-manual.html
index f6a405915f..a400fa3417 100644
--- a/testing/web-platform/tests/html/editing/dnd/events/dragleave-event-manual.html
+++ b/testing/web-platform/tests/html/editing/dnd/events/dragleave-event-manual.html
@@ -6,7 +6,6 @@
<link rel="author" title="Microsoft" href="http://www.microsoft.com/"/>
<link rel="help" href="http://dev.w3.org/html5/spec/dnd.html#drag-and-drop-processing-model"/>
<meta name="assert" content="Fire dragleave event during the drag and drop processing"/>
- <script src="../resources/dragdrop_support.js" type="text/javascript"></script>
<script type="text/javascript">
var EVENT, TARGET;
@@ -14,11 +13,11 @@
{
if ((TARGET == evt.target) && (EVENT == evt.type))
{
- LogTestResult("PASS");
+ document.getElementById("test_result").firstChild.data = "PASS";
}
else
{
- LogTestResult("FAIL");
+ document.getElementById("test_result").firstChild.data = "FAIL";
}
}
@@ -27,7 +26,7 @@
window.onload = function()
{
TARGET = document.getElementById("target");
- AddEventListenersForElement(EVENT, DragleaveEvent, false, TARGET);
+ TARGET.addEventListener(EVENT, DragleaveEvent, false);
}
</script>
</head>
diff --git a/testing/web-platform/tests/html/editing/dnd/events/dragover-event-manual.html b/testing/web-platform/tests/html/editing/dnd/events/dragover-event-manual.html
index f8d99241d5..f37a33cff6 100644
--- a/testing/web-platform/tests/html/editing/dnd/events/dragover-event-manual.html
+++ b/testing/web-platform/tests/html/editing/dnd/events/dragover-event-manual.html
@@ -6,7 +6,6 @@
<link rel="author" title="Microsoft" href="http://www.microsoft.com/"/>
<link rel="help" href="http://dev.w3.org/html5/spec/dnd.html#drag-and-drop-processing-model"/>
<meta name="assert" content="Fire dragover event during the drag and drop processing"/>
- <script src="../resources/dragdrop_support.js" type="text/javascript"></script>
<script type="text/javascript">
var EVENT, TARGET;
@@ -14,11 +13,11 @@
{
if ((TARGET == evt.target) && (EVENT == evt.type))
{
- LogTestResult("PASS");
+ document.getElementById("test_result").firstChild.data = "PASS";
}
else
{
- LogTestResult("FAIL");
+ document.getElementById("test_result").firstChild.data = "FAIL";
}
}
@@ -27,7 +26,7 @@
window.onload = function()
{
TARGET = document.getElementById("target");
- AddEventListenersForElement(EVENT, DragoverEvent, false, TARGET);
+ TARGET.addEventListener(EVENT, DragoverEvent, false);
}
</script>
</head>
diff --git a/testing/web-platform/tests/html/editing/dnd/events/dragstart-event-manual.html b/testing/web-platform/tests/html/editing/dnd/events/dragstart-event-manual.html
index 20786648da..9128401ffa 100644
--- a/testing/web-platform/tests/html/editing/dnd/events/dragstart-event-manual.html
+++ b/testing/web-platform/tests/html/editing/dnd/events/dragstart-event-manual.html
@@ -6,7 +6,6 @@
<link rel="author" title="Microsoft" href="http://www.microsoft.com/"/>
<link rel="help" href="http://dev.w3.org/html5/spec/dnd.html#drag-and-drop-processing-model"/>
<meta name="assert" content="Fire dragstart event during the drag and drop processing"/>
- <script src="../resources/dragdrop_support.js" type="text/javascript"></script>
<script type="text/javascript">
var EVENT, TARGET;
@@ -14,11 +13,11 @@
{
if ((TARGET == evt.target) && (EVENT == evt.type))
{
- LogTestResult("PASS");
+ document.getElementById("test_result").firstChild.data = "PASS";
}
else
{
- LogTestResult("FAIL");
+ document.getElementById("test_result").firstChild.data = "FAIL";
}
}
@@ -27,7 +26,7 @@
window.onload = function()
{
TARGET = document.getElementById("target");
- AddEventListenersForElement(EVENT, DragstartEvent, false, TARGET);
+ TARGET.addEventListener(EVENT, DragstartEvent, false);
}
</script>
</head>
diff --git a/testing/web-platform/tests/html/editing/dnd/events/drop-event-manual.html b/testing/web-platform/tests/html/editing/dnd/events/drop-event-manual.html
index 2897bd5713..8393e38696 100644
--- a/testing/web-platform/tests/html/editing/dnd/events/drop-event-manual.html
+++ b/testing/web-platform/tests/html/editing/dnd/events/drop-event-manual.html
@@ -6,7 +6,6 @@
<link rel="author" title="Microsoft" href="http://www.microsoft.com/"/>
<link rel="help" href="http://dev.w3.org/html5/spec/dnd.html#drag-and-drop-processing-model"/>
<meta name="assert" content="Fire drop event during the drag and drop processing"/>
- <script src="../resources/dragdrop_support.js" type="text/javascript"></script>
<script type="text/javascript">
var EVENT, TARGET;
@@ -14,11 +13,11 @@
{
if ((TARGET == evt.target) && (EVENT == evt.type))
{
- LogTestResult("PASS");
+ document.getElementById("test_result").firstChild.data = "PASS";
}
else
{
- LogTestResult("FAIL");
+ document.getElementById("test_result").firstChild.data = "FAIL";
}
}
@@ -27,7 +26,7 @@
window.onload = function()
{
TARGET = document.getElementById("target");
- AddEventListenersForElement(EVENT, DropEvent, false, TARGET);
+ TARGET.addEventListener(EVENT, DropEvent, false);
}
</script>
</head>
diff --git a/testing/web-platform/tests/html/editing/dnd/resources/dragdrop_support.js b/testing/web-platform/tests/html/editing/dnd/resources/dragdrop_support.js
deleted file mode 100644
index f5a1d6417f..0000000000
--- a/testing/web-platform/tests/html/editing/dnd/resources/dragdrop_support.js
+++ /dev/null
@@ -1,9 +0,0 @@
-function AddEventListenersForElement(evt, callback, capture, element)
-{
- element.addEventListener(evt, callback, capture);
-}
-
-function LogTestResult(result)
-{
- document.getElementById("test_result").firstChild.data = result;
-}
diff --git a/testing/web-platform/tests/html/editing/dnd/the-datatransfer-interface/effectAllowed-manual.html b/testing/web-platform/tests/html/editing/dnd/the-datatransfer-interface/effectAllowed-manual.html
index 08540b906a..61443da2c0 100644
--- a/testing/web-platform/tests/html/editing/dnd/the-datatransfer-interface/effectAllowed-manual.html
+++ b/testing/web-platform/tests/html/editing/dnd/the-datatransfer-interface/effectAllowed-manual.html
@@ -6,7 +6,6 @@
<link rel="author" title="Microsoft" href="http://www.microsoft.com/"/>
<link rel="help" href="http://dev.w3.org/html5/spec/dnd.html#datatransfer"/>
<meta name="assert" content="Set a value to effectAllowed attribute"/>
- <script src="../resources/dragdrop_support.js" type="text/javascript"></script>
<script type="text/javascript">
var TARGETEVENT1, TARGETEVENT2, TARGET1, TARGET2;
@@ -23,11 +22,11 @@
{
if("move" == evt.dataTransfer.effectAllowed)
{
- LogTestResult("PASS");
+ document.getElementById("test_result").firstChild.data = "PASS";
}
else
{
- LogTestResult("FAIL");
+ document.getElementById("test_result").firstChild.data = "FAIL";
}
}
}
@@ -39,8 +38,8 @@
{
TARGET1 = document.getElementById("target1");
TARGET2 = document.getElementById("target2");
- AddEventListenersForElement(TARGETEVENT1, DragstartEvent, false, TARGET1);
- AddEventListenersForElement(TARGETEVENT2, DragenterEvent, false, TARGET2);
+ TARGET1.addEventListener(TARGETEVENT1, DragstartEvent, false);
+ TARGET2.addEventListener(TARGETEVENT2, DragenterEvent, false);
}
</script>
</head>
diff --git a/testing/web-platform/tests/html/editing/dnd/the-datatransfer-interface/files-manual.html b/testing/web-platform/tests/html/editing/dnd/the-datatransfer-interface/files-manual.html
index 7de0b4bbce..ffafb66db4 100644
--- a/testing/web-platform/tests/html/editing/dnd/the-datatransfer-interface/files-manual.html
+++ b/testing/web-platform/tests/html/editing/dnd/the-datatransfer-interface/files-manual.html
@@ -6,7 +6,6 @@
<link rel="author" title="Microsoft" href="http://www.microsoft.com/"/>
<link rel="help" href="http://dev.w3.org/html5/spec/dnd.html#datatransfer"/>
<meta name="assert" content="files attribute returns a FileList"/>
- <script src="../resources/dragdrop_support.js" type="text/javascript"></script>
<script type="text/javascript">
var EVENT, TARGET;
@@ -17,16 +16,16 @@
var files = evt.dataTransfer.files;
if(('[object FileList]' == files))
{
- LogTestResult("PASS");
+ document.getElementById("test_result").firstChild.data = "PASS";
}
else
{
- LogTestResult("FAIL");
+ document.getElementById("test_result").firstChild.data = "FAIL";
}
}
else
{
- LogTestResult("FAIL");
+ document.getElementById("test_result").firstChild.data = "FAIL";
}
}
@@ -45,9 +44,9 @@
window.onload = function()
{
TARGET = document.getElementById("target");
- AddEventListenersForElement(EVENT, DropEvent, false, TARGET);
- AddEventListenersForElement("dragenter", DragenterEvent, false, TARGET);
- AddEventListenersForElement("dragover", DragoverEvent, false, TARGET);
+ TARGET.addEventListener(EVENT, DropEvent, false);
+ TARGET.addEventListener("dragenter", DragenterEvent, false);
+ TARGET.addEventListener("dragover", DragoverEvent, false);
}
</script>
</head>
diff --git a/testing/web-platform/tests/html/editing/dnd/the-datatransfer-interface/setData-manual.html b/testing/web-platform/tests/html/editing/dnd/the-datatransfer-interface/setData-manual.html
index f0f7cae600..1438e932ad 100644
--- a/testing/web-platform/tests/html/editing/dnd/the-datatransfer-interface/setData-manual.html
+++ b/testing/web-platform/tests/html/editing/dnd/the-datatransfer-interface/setData-manual.html
@@ -6,7 +6,6 @@
<link rel="author" title="Microsoft" href="http://www.microsoft.com/"/>
<link rel="help" href="http://dev.w3.org/html5/spec/dnd.html#datatransfer"/>
<meta name="assert" content="Add an item to the drag data store item list whose data is the string given by setData method's second argument"/>
- <script src="../resources/dragdrop_support.js" type="text/javascript"></script>
<script type="text/javascript">
var TARGETEVENT1, TARGETEVENT2, TARGET1, TARGET2;
@@ -23,11 +22,11 @@
{
if("SetText" == evt.dataTransfer.getData("text"))
{
- LogTestResult("PASS");
+ document.getElementById("test_result").firstChild.data = "PASS";
}
else
{
- LogTestResult("FAIL");
+ document.getElementById("test_result").firstChild.data = "FAIL";
}
}
}
@@ -39,8 +38,8 @@
{
TARGET1 = document.getElementById("target1");
TARGET2 = document.getElementById("target2");
- AddEventListenersForElement(TARGETEVENT1, DragstartEvent, false, TARGET1);
- AddEventListenersForElement(TARGETEVENT2, DropEvent, false, TARGET2);
+ TARGET1.addEventListener(TARGETEVENT1, DragstartEvent, false);
+ TARGET2.addEventListener(TARGETEVENT2, DropEvent, false);
}
</script>
</head>
diff --git a/testing/web-platform/tests/html/editing/dnd/the-datatransfer-interface/types-manual.html b/testing/web-platform/tests/html/editing/dnd/the-datatransfer-interface/types-manual.html
index 1730c4bc73..3aa1404e29 100644
--- a/testing/web-platform/tests/html/editing/dnd/the-datatransfer-interface/types-manual.html
+++ b/testing/web-platform/tests/html/editing/dnd/the-datatransfer-interface/types-manual.html
@@ -6,7 +6,6 @@
<link rel="author" title="Microsoft" href="http://www.microsoft.com/"/>
<link rel="help" href="http://dev.w3.org/html5/spec/dnd.html#datatransfer"/>
<meta name="assert" content="types attribute returns a DOMStringList"/>
- <script src="../resources/dragdrop_support.js" type="text/javascript"></script>
<script type="text/javascript">
var EVENT, TARGET;
@@ -17,16 +16,16 @@
var types = evt.dataTransfer.types;
if(('[object DOMStringList]' == types))
{
- LogTestResult("PASS");
+ document.getElementById("test_result").firstChild.data = "PASS";
}
else
{
- LogTestResult("FAIL");
+ document.getElementById("test_result").firstChild.data = "FAIL";
}
}
else
{
- LogTestResult("FAIL");
+ document.getElementById("test_result").firstChild.data = "FAIL";
}
}
@@ -35,7 +34,7 @@
window.onload = function()
{
TARGET = document.getElementById("target");
- AddEventListenersForElement(EVENT, DropEvent, false, TARGET);
+ TARGET.addEventListener(EVENT, DropEvent, false);
}
</script>
</head>
diff --git a/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/window-simple-success.https.html b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/window-simple-success.https.html
index c9b41d0a0d..5be96d37a4 100644
--- a/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/window-simple-success.https.html
+++ b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/window-simple-success.https.html
@@ -23,6 +23,7 @@
"Uint32Array",
"BigInt64Array",
"BigUint64Array",
+ "Float16Array",
"Float32Array",
"Float64Array"
].forEach(type => {
diff --git a/testing/web-platform/tests/html/interaction/focus/WEB_FEATURES.yml b/testing/web-platform/tests/html/interaction/focus/WEB_FEATURES.yml
new file mode 100644
index 0000000000..210e2d3f99
--- /dev/null
+++ b/testing/web-platform/tests/html/interaction/focus/WEB_FEATURES.yml
@@ -0,0 +1,4 @@
+features:
+- name: tabindex
+ files:
+ - tabindex-focus-flag.html
diff --git a/testing/web-platform/tests/html/interaction/focus/sequential-focus-navigation-and-the-tabindex-attribute/WEB_FEATURES.yml b/testing/web-platform/tests/html/interaction/focus/sequential-focus-navigation-and-the-tabindex-attribute/WEB_FEATURES.yml
new file mode 100644
index 0000000000..6d868044c9
--- /dev/null
+++ b/testing/web-platform/tests/html/interaction/focus/sequential-focus-navigation-and-the-tabindex-attribute/WEB_FEATURES.yml
@@ -0,0 +1,3 @@
+features:
+- name: tabindex
+ files: "**"
diff --git a/testing/web-platform/tests/html/meta/refresh-time.html b/testing/web-platform/tests/html/meta/refresh-time.html
new file mode 100644
index 0000000000..7aef1266a2
--- /dev/null
+++ b/testing/web-platform/tests/html/meta/refresh-time.html
@@ -0,0 +1,53 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>Test fractional values in meta http-equiv=refresh</title>
+<link rel="author" title="Psychpsyo" href="mailto:psychpsyo@gmail.com">
+<link rel="help" href="https://html.spec.whatwg.org/#pragma-directives">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<body>
+<script>
+ async function sleep(ms, test) {
+ return new Promise(resolve => {test.step_timeout(resolve, ms)});
+ }
+
+ promise_test(async test => {
+ const frame = document.createElement("iframe");
+ document.body.appendChild(frame);
+ frame.src = "resources/refresh1.html";
+ await sleep(500, test);
+ assert_equals(frame.contentWindow.document.title, "refresh 1");
+ await sleep(1000, test);
+ assert_equals(frame.contentWindow.document.title, "got refreshed");
+ }, "Ensure that refresh is observed");
+
+ promise_test(async test => {
+ const frame = document.createElement("iframe");
+ document.body.appendChild(frame);
+ frame.src = "resources/refresh.99.html";
+ await sleep(500, test);
+ assert_equals(frame.contentWindow.document.title, "got refreshed");
+ }, "Ensure that fractions in refresh time are ignored");
+
+ promise_test(async test => {
+ const frame = document.createElement("iframe");
+ document.body.appendChild(frame);
+ frame.src = "resources/refresh1.99.html";
+ await sleep(500, test);
+ assert_equals(frame.contentWindow.document.title, "refresh 1.99");
+ await sleep(1000, test);
+ assert_equals(frame.contentWindow.document.title, "got refreshed");
+ }, "Ensure that non-fractional part in refresh time does not get discarded");
+
+ promise_test(async test => {
+ const frame = document.createElement("iframe");
+ document.body.appendChild(frame);
+ frame.src = "resources/refresh1dotdot5dot.html";
+ await sleep(500, test);
+ assert_equals(frame.contentWindow.document.title, "refresh 1..5.");
+ await sleep(750, test);
+ assert_equals(frame.contentWindow.document.title, "got refreshed");
+ }, "Ensure that multiple periods in refresh time just get ignored");
+</script>
+</body> \ No newline at end of file
diff --git a/testing/web-platform/tests/html/meta/resources/gotRefreshed.html b/testing/web-platform/tests/html/meta/resources/gotRefreshed.html
new file mode 100644
index 0000000000..c894269593
--- /dev/null
+++ b/testing/web-platform/tests/html/meta/resources/gotRefreshed.html
@@ -0,0 +1,3 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>got refreshed</title> \ No newline at end of file
diff --git a/testing/web-platform/tests/html/meta/resources/refresh.99.html b/testing/web-platform/tests/html/meta/resources/refresh.99.html
new file mode 100644
index 0000000000..ca4e346277
--- /dev/null
+++ b/testing/web-platform/tests/html/meta/resources/refresh.99.html
@@ -0,0 +1,5 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>refresh .99</title>
+
+<meta http-equiv="refresh" content=".99;url=gotRefreshed.html"> \ No newline at end of file
diff --git a/testing/web-platform/tests/html/meta/resources/refresh1.99.html b/testing/web-platform/tests/html/meta/resources/refresh1.99.html
new file mode 100644
index 0000000000..76121cfd40
--- /dev/null
+++ b/testing/web-platform/tests/html/meta/resources/refresh1.99.html
@@ -0,0 +1,5 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>refresh 1.99</title>
+
+<meta http-equiv="refresh" content="1.99;url=gotRefreshed.html"> \ No newline at end of file
diff --git a/testing/web-platform/tests/html/meta/resources/refresh1.html b/testing/web-platform/tests/html/meta/resources/refresh1.html
new file mode 100644
index 0000000000..14819dc3db
--- /dev/null
+++ b/testing/web-platform/tests/html/meta/resources/refresh1.html
@@ -0,0 +1,5 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>refresh 1</title>
+
+<meta http-equiv="refresh" content="1;url=gotRefreshed.html"> \ No newline at end of file
diff --git a/testing/web-platform/tests/html/meta/resources/refresh1dotdot5dot.html b/testing/web-platform/tests/html/meta/resources/refresh1dotdot5dot.html
new file mode 100644
index 0000000000..085b9e9ba7
--- /dev/null
+++ b/testing/web-platform/tests/html/meta/resources/refresh1dotdot5dot.html
@@ -0,0 +1,5 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>refresh 1..5.</title>
+
+<meta http-equiv="refresh" content="1..5.;url=gotRefreshed.html"> \ No newline at end of file
diff --git a/testing/web-platform/tests/html/rendering/non-replaced-elements/flow-content-0/WEB_FEATURES.yml b/testing/web-platform/tests/html/rendering/non-replaced-elements/flow-content-0/WEB_FEATURES.yml
new file mode 100644
index 0000000000..831b257f72
--- /dev/null
+++ b/testing/web-platform/tests/html/rendering/non-replaced-elements/flow-content-0/WEB_FEATURES.yml
@@ -0,0 +1,4 @@
+features:
+- name: search
+ files:
+ - search-*
diff --git a/testing/web-platform/tests/html/rendering/replaced-elements/the-select-element/select-1-block-size-001-ref-2.html b/testing/web-platform/tests/html/rendering/replaced-elements/the-select-element/select-1-block-size-001-ref-2.html
index 385c2a75d4..5246123186 100644
--- a/testing/web-platform/tests/html/rendering/replaced-elements/the-select-element/select-1-block-size-001-ref-2.html
+++ b/testing/web-platform/tests/html/rendering/replaced-elements/the-select-element/select-1-block-size-001-ref-2.html
@@ -9,7 +9,7 @@ div {
appearance: none;
background: black;
- color: black;
+ color: transparent;
line-height: 100px;
width: 100px;
diff --git a/testing/web-platform/tests/html/rendering/replaced-elements/the-select-element/select-1-block-size-001-ref.html b/testing/web-platform/tests/html/rendering/replaced-elements/the-select-element/select-1-block-size-001-ref.html
index 3834281dd8..3d30c2bd9d 100644
--- a/testing/web-platform/tests/html/rendering/replaced-elements/the-select-element/select-1-block-size-001-ref.html
+++ b/testing/web-platform/tests/html/rendering/replaced-elements/the-select-element/select-1-block-size-001-ref.html
@@ -10,7 +10,7 @@ button {
appearance: none;
background: black;
- color: black;
+ color: transparent;
line-height: 100px;
width: 100px;
diff --git a/testing/web-platform/tests/html/rendering/the-details-element/WEB_FEATURES.yml b/testing/web-platform/tests/html/rendering/the-details-element/WEB_FEATURES.yml
new file mode 100644
index 0000000000..769e741180
--- /dev/null
+++ b/testing/web-platform/tests/html/rendering/the-details-element/WEB_FEATURES.yml
@@ -0,0 +1,3 @@
+features:
+- name: details
+ files: "**"
diff --git a/testing/web-platform/tests/html/rendering/widgets/input-password-background-suppresses-appearance-ref.html b/testing/web-platform/tests/html/rendering/widgets/input-password-background-suppresses-appearance-ref.html
new file mode 100644
index 0000000000..33e0e6ac16
--- /dev/null
+++ b/testing/web-platform/tests/html/rendering/widgets/input-password-background-suppresses-appearance-ref.html
@@ -0,0 +1,3 @@
+<!doctype html>
+<meta charset="utf-8">
+<input type="password" style="appearance: none; background-color: blue">
diff --git a/testing/web-platform/tests/html/rendering/widgets/input-password-background-suppresses-appearance.html b/testing/web-platform/tests/html/rendering/widgets/input-password-background-suppresses-appearance.html
new file mode 100644
index 0000000000..3c85b100a1
--- /dev/null
+++ b/testing/web-platform/tests/html/rendering/widgets/input-password-background-suppresses-appearance.html
@@ -0,0 +1,7 @@
+<!doctype html>
+<meta charset="utf-8">
+<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1895561">
+<link rel="author" title="Emilio Cobos Álvarez" href="mailto:emilio@crisal.io">
+<link rel="match" href="input-password-background-suppresses-appearance-ref.html">
+<title>backgrounds disable native password input appearance</title>
+<input type="password" style="background-color: blue">
diff --git a/testing/web-platform/tests/html/semantics/embedded-content/media-elements/WEB_FEATURES.yml b/testing/web-platform/tests/html/semantics/embedded-content/media-elements/WEB_FEATURES.yml
new file mode 100644
index 0000000000..5730fe4715
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/embedded-content/media-elements/WEB_FEATURES.yml
@@ -0,0 +1,4 @@
+features:
+- name: preserves-pitch
+ files:
+ - preserves-pitch.html
diff --git a/testing/web-platform/tests/html/semantics/embedded-content/the-object-element/WEB_FEATURES.yml b/testing/web-platform/tests/html/semantics/embedded-content/the-object-element/WEB_FEATURES.yml
new file mode 100644
index 0000000000..d3411c2d8d
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/embedded-content/the-object-element/WEB_FEATURES.yml
@@ -0,0 +1,4 @@
+features:
+- name: constraint-validation
+ files:
+ - object-setcustomvalidity.html
diff --git a/testing/web-platform/tests/html/semantics/forms/attributes-common-to-form-controls/WEB_FEATURES.yml b/testing/web-platform/tests/html/semantics/forms/attributes-common-to-form-controls/WEB_FEATURES.yml
new file mode 100644
index 0000000000..457c904005
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/attributes-common-to-form-controls/WEB_FEATURES.yml
@@ -0,0 +1,4 @@
+features:
+- name: dirname
+ files:
+ - dirname-*
diff --git a/testing/web-platform/tests/html/semantics/forms/constraints/WEB_FEATURES.yml b/testing/web-platform/tests/html/semantics/forms/constraints/WEB_FEATURES.yml
new file mode 100644
index 0000000000..93b4c5745f
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/constraints/WEB_FEATURES.yml
@@ -0,0 +1,3 @@
+features:
+- name: constraint-validation
+ files: "**"
diff --git a/testing/web-platform/tests/html/semantics/forms/constraints/form-validation-validity-textarea-defaultValue.html b/testing/web-platform/tests/html/semantics/forms/constraints/form-validation-validity-textarea-defaultValue.html
new file mode 100644
index 0000000000..55276116ad
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/constraints/form-validation-validity-textarea-defaultValue.html
@@ -0,0 +1,98 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>textarea validation behavior</title>
+<link rel="author" href="mailto:masonf@chromium.org">
+<link rel="help" href="https://html.spec.whatwg.org/multipage/#suffering-from-being-too-short">
+<link rel="help" href="https://html.spec.whatwg.org/multipage/#the-constraint-validation-api">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
+
+<textarea id=t1 minlength=5 required></textarea>
+<textarea id=t2 minlength=5 required>a</textarea>
+<textarea id=t3 required>a</textarea>
+<textarea id=t4>a</textarea>
+<script>
+test(() => {
+ const emptyMinlength = document.getElementById('t1');
+ const nonEmptyMinlength = document.getElementById('t2');
+ const nonEmptyRequired = document.getElementById('t3');
+ const nonEmptyNonRequired = document.getElementById('t4');
+ assert_false(emptyMinlength.validity.valid,'Empty textareas with constraints will validate');
+ assert_true(nonEmptyMinlength.validity.valid,'Non-empty textareas with constraints will *not* validate');
+ assert_true(nonEmptyRequired.validity.valid,'Textareas without constraints will validate');
+ assert_true(nonEmptyNonRequired.validity.valid,'Textareas without constraints will validate');
+ [t1,t2,t3,t4].forEach(t => t.remove());
+},'Default validity based on emptiness');
+</script>
+
+<textarea id=t5 minlength=5 required></textarea>
+<script>
+promise_test(async () => {
+ const textarea = document.getElementById('t5');
+ document.querySelector('#t1');
+ assert_false(textarea.validity.valid,'By default, this textarea will validate (and fail) because it started empty');
+ textarea.defaultValue = 'abc';
+ assert_true(textarea.validity.valid,'Programmatically setting defaultValue is not a user edit - automatically valid');
+ textarea.replaceChildren('abcd');
+ assert_true(textarea.validity.valid,'Programmatically replacing children is not a user edit - automatically valid');
+ textarea.defaultValue = 'abcde';
+ assert_true(textarea.validity.valid,'Still valid');
+ textarea.remove();
+},'Setting textarea.defaultValue should not trigger validation');
+</script>
+
+<textarea id=t6 minlength=5 required></textarea>
+<script>
+promise_test(async () => {
+ const textarea = document.getElementById('t6');
+ assert_false(textarea.validity.valid,'By default, this textarea will validate (and fail) because it started empty');
+ await test_driver.send_keys(textarea, "abc");
+ assert_false(textarea.validity.valid,'Keystrokes should trigger validation, which will fail (length 3)');
+ await test_driver.send_keys(textarea, "de");
+ assert_equals(textarea.value,"abcde");
+ assert_true(textarea.validity.valid,'Now valid');
+ textarea.remove();
+},'User keystrokes should trigger validation');
+</script>
+
+<textarea id=t7 minlength=5 required></textarea>
+<script>
+promise_test(async () => {
+ const textarea = document.getElementById('t7');
+ textarea.addEventListener('input', (e) => {
+ e.target.defaultValue = e.target.value;
+ });
+ assert_false(textarea.validity.valid,'By default, this textarea will validate (and fail) because it started empty');
+ await test_driver.send_keys(textarea, "abc");
+ assert_equals(textarea.value,"abc");
+ assert_false(textarea.validity.valid,'Still invalid with 3 characters');
+ await test_driver.send_keys(textarea, "de");
+ assert_equals(textarea.value,"abcde");
+ assert_true(textarea.validity.valid,'With 5 characters, now valid');
+ textarea.remove();
+},'Setting textarea.defaultValue from the input event handler should trigger validation');
+</script>
+
+<textarea id=t8 minlength=5 required></textarea>
+<script>
+promise_test(async () => {
+ const textarea = document.getElementById('t8');
+ textarea.addEventListener('input', (e) => {
+ e.target.replaceChildren(e.target.value);
+ });
+ assert_false(textarea.validity.valid,'By default, this textarea will validate (and fail) because it started empty');
+ await test_driver.send_keys(textarea, "abc");
+ assert_equals(textarea.value,"abc");
+ assert_false(textarea.validity.valid,'Still invalid with 3 characters');
+ await test_driver.send_keys(textarea, "de");
+ assert_equals(textarea.value,"abcde");
+ assert_true(textarea.validity.valid,'With 5 characters, now valid');
+ textarea.remove();
+},'Calling textarea.replaceChildren() from the input event handler should trigger validation');
+</script>
+
+<style>
+ :invalid { background-color: rgb(248, 203, 203); }
+</style>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-button-element/WEB_FEATURES.yml b/testing/web-platform/tests/html/semantics/forms/the-button-element/WEB_FEATURES.yml
new file mode 100644
index 0000000000..f5a2aeaf4f
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-button-element/WEB_FEATURES.yml
@@ -0,0 +1,10 @@
+features:
+- name: constraint-validation
+ files:
+ - button-checkvalidity.html
+ - button-setcustomvalidity.html
+ - button-validation.html
+ - button-validationmessage.html
+ - button-validity.html
+ - button-willvalidate-readonly-attribute.html
+ - button-willvalidate.html
diff --git a/testing/web-platform/tests/html/semantics/forms/the-fieldset-element/WEB_FEATURES.yml b/testing/web-platform/tests/html/semantics/forms/the-fieldset-element/WEB_FEATURES.yml
new file mode 100644
index 0000000000..912cb47c6d
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-fieldset-element/WEB_FEATURES.yml
@@ -0,0 +1,8 @@
+features:
+- name: constraint-validation
+ files:
+ - fieldset-checkvalidity.html
+ - fieldset-setcustomvalidity.html
+ - fieldset-validationmessage.html
+ - fieldset-validity.html
+ - fieldset-willvalidate.html
diff --git a/testing/web-platform/tests/html/semantics/forms/the-form-element/WEB_FEATURES.yml b/testing/web-platform/tests/html/semantics/forms/the-form-element/WEB_FEATURES.yml
new file mode 100644
index 0000000000..04c20cb5ec
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-form-element/WEB_FEATURES.yml
@@ -0,0 +1,4 @@
+features:
+- name: constraint-validation
+ files:
+ - form-checkvalidity.html
diff --git a/testing/web-platform/tests/html/semantics/forms/the-input-element/WEB_FEATURES.yml b/testing/web-platform/tests/html/semantics/forms/the-input-element/WEB_FEATURES.yml
new file mode 100644
index 0000000000..4957615f24
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-input-element/WEB_FEATURES.yml
@@ -0,0 +1,11 @@
+features:
+- name: constraint-validation
+ files:
+ - input-checkvalidity.html
+ - input-setcustomvalidity.html
+ - input-validationmessage.html
+ - input-validity.html
+ - input-willvalidate.html
+- name: show-picker-input
+ files:
+ - show-picker-*
diff --git a/testing/web-platform/tests/html/semantics/forms/the-input-element/input-stepdown-02.html b/testing/web-platform/tests/html/semantics/forms/the-input-element/input-stepdown-02.html
new file mode 100644
index 0000000000..db71d11009
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-input-element/input-stepdown-02.html
@@ -0,0 +1,42 @@
+<!DOCTYPE HTML>
+<title>Input Step Down</title>
+
+<link rel="help" href="https://html.spec.whatwg.org/multipage/input.html#dom-input-stepup">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<input type='number' id='input'>
+
+<script>
+ const input = document.getElementById("input");
+
+ function testStepDown(initialValue, minValue, expectedValue) {
+ input.value = initialValue;
+ input.min = minValue;
+
+ input.stepDown();
+
+ assert_equals(input.value, expectedValue);
+ }
+
+ const tests = [
+ { initialValue: '', minValue: '', expectedValue: '-1', description: 'stepDown() on input with no initial or min values' },
+ { initialValue: '', minValue: '7', expectedValue: '7', description: 'stepDown() on input with no initial value and positive min value' },
+ { initialValue: '', minValue: '-7', expectedValue: '-1', description: 'stepDown() on input with no initial value and negative min value' },
+ { initialValue: '7', minValue: '7', expectedValue: '7', description: 'stepDown() on input with initial value equal to min value' },
+ { initialValue: '3', minValue: '7', expectedValue: '3', description: 'stepDown() on input with initial value less than min value' },
+ { initialValue: '10', minValue: '7', expectedValue: '9', description: 'stepDown() on input with initial value greater than min value' },
+ ];
+
+ for(const t of tests) {
+ test(()=>{
+ testStepDown(
+ t.initialValue,
+ t.minValue,
+ t.expectedValue
+ );
+ },
+ t.description);
+ }
+</script>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-output-element/WEB_FEATURES.yml b/testing/web-platform/tests/html/semantics/forms/the-output-element/WEB_FEATURES.yml
new file mode 100644
index 0000000000..2f7f8e8cc2
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-output-element/WEB_FEATURES.yml
@@ -0,0 +1,5 @@
+features:
+- name: constraint-validation
+ files:
+ - output-setcustomvalidity.html
+ - output-validity.html
diff --git a/testing/web-platform/tests/html/semantics/forms/the-select-element/WEB_FEATURES.yml b/testing/web-platform/tests/html/semantics/forms/the-select-element/WEB_FEATURES.yml
new file mode 100644
index 0000000000..9695c95294
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-select-element/WEB_FEATURES.yml
@@ -0,0 +1,9 @@
+features:
+- name: constraint-validation
+ files:
+ - select-setcustomvalidity.html
+ - select-validity.html
+ - select-willvalidate-readonly-attribute.html
+- name: show-picker-select
+ files:
+ - show-picker-*
diff --git a/testing/web-platform/tests/html/semantics/forms/the-select-element/stylable-select/native-popup-with-datalist-ref.html b/testing/web-platform/tests/html/semantics/forms/the-select-element/stylable-select/native-popup-with-datalist-ref.html
new file mode 100644
index 0000000000..87918b6a92
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-select-element/stylable-select/native-popup-with-datalist-ref.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
+
+<select>
+ <option>one</option>
+ <hr>
+ <option>two</option>
+</select>
+
+<script>
+(async () => {
+ await test_driver.click(document.querySelector('select'));
+ document.documentElement.classList.remove('reftest-wait');
+})();
+</script>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-select-element/stylable-select/native-popup-with-datalist.tentative.html b/testing/web-platform/tests/html/semantics/forms/the-select-element/stylable-select/native-popup-with-datalist.tentative.html
new file mode 100644
index 0000000000..a968c6a164
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-select-element/stylable-select/native-popup-with-datalist.tentative.html
@@ -0,0 +1,25 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<link rel=author href="mailto:jarhar@chromium.org">
+<link rel=help href="https://github.com/whatwg/html/issues/9799">
+<link rel=match href="native-popup-with-datalist-ref.html">
+<link rel=assert title="The native popup of a select should show options descending from datalists">
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
+
+<select>
+ <datalist>
+ <div>
+ <option>one</option>
+ <hr>
+ <option>two</option>
+ </div>
+ </datalist>
+</select>
+
+<script>
+(async () => {
+ await test_driver.click(document.querySelector('select'));
+ document.documentElement.classList.remove('reftest-wait');
+})();
+</script>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-select-element/stylable-select/nested-options.tenative.html b/testing/web-platform/tests/html/semantics/forms/the-select-element/stylable-select/nested-options.tenative.html
new file mode 100644
index 0000000000..7e89a5ad42
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-select-element/stylable-select/nested-options.tenative.html
@@ -0,0 +1,46 @@
+<!DOCTYPE html>
+<link rel=author href="mailto:jarhar@chromium.org">
+<link rel=help href="https://bugs.chromium.org/p/chromium/issues/detail?id=1422275">
+<link rel=help href="https://chromium-review.googlesource.com/c/chromium/src/+/5441435/1#message-cd8841d92a672a0276ab536dfaf3a20e93d5e6e3">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
+
+<select>
+ <datalist>
+ <option id=o1>
+ parent
+ <option id=o2>child</option>
+</option>
+ </datalist>
+</select>
+
+<script>
+const select = document.querySelector('select');
+
+test(() => {
+ assert_equals(select.innerHTML, `
+ <datalist>
+ <option id="o1">
+ parent
+ </option><option id="o2">child</option>
+
+ </datalist>
+`);
+}, 'The HTML parser should disallow nested options in select datalist.');
+
+// Manually nest the <options> anyway for the following tests.
+o1.appendChild(o2);
+
+test(() => {
+ assert_equals(select.options.length, 2, 'select.options.length');
+ assert_equals(select.options[0], o1, 'select.options[0]');
+ assert_equals(select.options[1], o2, 'select.options[1]');
+}, 'Nested <options> should be listed in <select> IDLs.');
+
+promise_test(async () => {
+ await test_driver.bless();
+ select.showPicker();
+}, 'Showing the popup with nested <option>s should not crash.');
+</script>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-select-element/stylable-select/resources/select-reset-non-interoperable-styles.css b/testing/web-platform/tests/html/semantics/forms/the-select-element/stylable-select/resources/select-reset-non-interoperable-styles.css
deleted file mode 100644
index d2b9d9df26..0000000000
--- a/testing/web-platform/tests/html/semantics/forms/the-select-element/stylable-select/resources/select-reset-non-interoperable-styles.css
+++ /dev/null
@@ -1,5 +0,0 @@
-/* TODO(crbug.com/1511354): linux.css sets background-color on select, consider
- * removing it. */
-select {
- background-color: Field;
-}
diff --git a/testing/web-platform/tests/html/semantics/forms/the-select-element/stylable-select/resources/stylable-select-styles.css b/testing/web-platform/tests/html/semantics/forms/the-select-element/stylable-select/resources/stylable-select-styles.css
index 042de838d1..5ee317d61a 100644
--- a/testing/web-platform/tests/html/semantics/forms/the-select-element/stylable-select/resources/stylable-select-styles.css
+++ b/testing/web-platform/tests/html/semantics/forms/the-select-element/stylable-select/resources/stylable-select-styles.css
@@ -1,9 +1,6 @@
/* These are UA styles for select and stylable select. */
.stylable-select-container {
- background-color: Field;
- border: 1px solid rgba(0, 0, 0, 0);
- border-radius: 0;
box-sizing: border-box;
display: inline-block;
}
@@ -14,7 +11,8 @@
overflow: auto;
border: 1px solid rgba(0, 0, 0, 0.15);
border-radius: 0.25em;
- padding: 0.25em 0;
+ padding-block: 0.25em;
+ padding-inline: 0;
background-color: Field;
margin: 0;
inset: auto;
@@ -35,3 +33,46 @@
padding: 0px 2px 1px;
white-space: nowrap;
}
+
+.stylable-select-button {
+ color: FieldText;
+ background-color: Field;
+ appearance: none;
+ padding: 0.25em;
+ border: 1px solid ButtonBorder;
+ cursor: default;
+ text-align: inherit;
+ display: inline-flex;
+ flex-grow: 1;
+ flex-shrink: 1;
+ align-items: center;
+ overflow-x: hidden;
+ overflow-y: hidden;
+}
+
+.stylable-select-button-icon {
+ background-image: url(data:image/svg+xml,%3Csvg%20width%3D%2220%22%20height%3D%2214%22%20viewBox%3D%220%200%2020%2016%22%20fill%3D%22none%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%3Cpath%20d%3D%22M4%206%20L10%2012%20L%2016%206%22%20stroke%3D%22WindowText%22%20stroke-width%3D%223%22%20stroke-linejoin%3D%22round%22%2F%3E%3C%2Fsvg%3E);
+ background-origin: content-box;
+ background-repeat: no-repeat;
+ background-size: contain;
+ opacity: 1;
+ outline: none;
+ margin-inline-start: 0.25em;
+ padding-block: 2px;
+ padding-inline: 3px;
+ block-size: 1.0em;
+ inline-size: 1.2em;
+ min-inline-size: 1.2em;
+ max-inline-size: 1.2em;
+ display: block;
+}
+
+.stylable-select-selectedoption {
+ color: inherit;
+ min-inline-size: 0px;
+ max-block-size: 100%;
+ flex-grow: 1;
+ flex-shrink: 1;
+ overflow: hidden;
+ display: inline;
+}
diff --git a/testing/web-platform/tests/html/semantics/forms/the-select-element/stylable-select/select-appearance-no-button-custom-datalist-ref.html b/testing/web-platform/tests/html/semantics/forms/the-select-element/stylable-select/select-appearance-custom-button-no-datalist-ref.html
index 8e5eadaf57..10c966a107 100644
--- a/testing/web-platform/tests/html/semantics/forms/the-select-element/stylable-select/select-appearance-no-button-custom-datalist-ref.html
+++ b/testing/web-platform/tests/html/semantics/forms/the-select-element/stylable-select/select-appearance-custom-button-no-datalist-ref.html
@@ -2,7 +2,7 @@
<link rel=stylesheet href="resources/stylable-select-styles.css">
<div id=container class=stylable-select-container>
- <button popovertarget=popover id=button>one</button>
+ <button>one</button>
<div id=popover popover=auto anchor=container class=stylable-select-datalist>
<div class=stylable-select-option>one</div>
<div class=stylable-select-option>two</div>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-select-element/stylable-select/select-appearance-custom-button-no-datalist.tentative.html b/testing/web-platform/tests/html/semantics/forms/the-select-element/stylable-select/select-appearance-custom-button-no-datalist.tentative.html
index 94d7fd53b3..aaceabcf05 100644
--- a/testing/web-platform/tests/html/semantics/forms/the-select-element/stylable-select/select-appearance-custom-button-no-datalist.tentative.html
+++ b/testing/web-platform/tests/html/semantics/forms/the-select-element/stylable-select/select-appearance-custom-button-no-datalist.tentative.html
@@ -2,8 +2,7 @@
<html class=reftest-wait>
<link rel=author href="mailto:jarhar@chromium.org">
<link rel=help href="https://github.com/whatwg/html/issues/9799">
-<link rel=match href="select-appearance-no-button-custom-datalist-ref.html">
-<link rel=stylesheet href="resources/select-reset-non-interoperable-styles.css">
+<link rel=match href="select-appearance-custom-button-no-datalist-ref.html">
<script src="/resources/testdriver.js"></script>
<script src="/resources/testdriver-vendor.js"></script>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-select-element/stylable-select/select-appearance-no-button-custom-datalist.tentative.html b/testing/web-platform/tests/html/semantics/forms/the-select-element/stylable-select/select-appearance-no-button-custom-datalist.tentative.html
index 87425cf7a3..cc8a4c60bd 100644
--- a/testing/web-platform/tests/html/semantics/forms/the-select-element/stylable-select/select-appearance-no-button-custom-datalist.tentative.html
+++ b/testing/web-platform/tests/html/semantics/forms/the-select-element/stylable-select/select-appearance-no-button-custom-datalist.tentative.html
@@ -2,8 +2,7 @@
<html class=reftest-wait>
<link rel=author href="mailto:jarhar@chromium.org">
<link rel=help href="https://github.com/whatwg/html/issues/9799">
-<link rel=match href="select-appearance-no-button-custom-datalist-ref.html">
-<link rel=stylesheet href="resources/select-reset-non-interoperable-styles.css">
+<link rel=match href="select-appearance-no-button-no-datalist-ref.html">
<script src="/resources/testdriver.js"></script>
<script src="/resources/testdriver-vendor.js"></script>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-select-element/stylable-select/select-appearance-no-button-no-datalist-ref.html b/testing/web-platform/tests/html/semantics/forms/the-select-element/stylable-select/select-appearance-no-button-no-datalist-ref.html
new file mode 100644
index 0000000000..3c6e9416b0
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-select-element/stylable-select/select-appearance-no-button-no-datalist-ref.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<link rel=stylesheet href="resources/stylable-select-styles.css">
+
+<div id=container class=stylable-select-container>
+ <button class=stylable-select-button popovertarget=popover id=button>
+ <span class=stylable-select-selectedoption>one</span>
+ <div class=stylable-select-button-icon></div>
+ </button>
+ <div id=popover popover=auto anchor=container class=stylable-select-datalist>
+ <div class=stylable-select-option>one</div>
+ <div class=stylable-select-option>two</div>
+ </div>
+</div>
+
+<script>
+document.getElementById('popover').showPopover();
+</script>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-select-element/stylable-select/select-appearance-no-button-no-datalist.tentative.html b/testing/web-platform/tests/html/semantics/forms/the-select-element/stylable-select/select-appearance-no-button-no-datalist.tentative.html
index b2a6b5a6d3..29261b7f25 100644
--- a/testing/web-platform/tests/html/semantics/forms/the-select-element/stylable-select/select-appearance-no-button-no-datalist.tentative.html
+++ b/testing/web-platform/tests/html/semantics/forms/the-select-element/stylable-select/select-appearance-no-button-no-datalist.tentative.html
@@ -2,8 +2,7 @@
<html class=reftest-wait>
<link rel=author href="mailto:jarhar@chromium.org">
<link rel=help href="https://github.com/whatwg/html/issues/9799">
-<link rel=match href="select-appearance-no-button-custom-datalist-ref.html">
-<link rel=stylesheet href="resources/select-reset-non-interoperable-styles.css">
+<link rel=match href="select-appearance-no-button-no-datalist-ref.html">
<script src="/resources/testdriver.js"></script>
<script src="/resources/testdriver-vendor.js"></script>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-select-element/stylable-select/select-appearance-writing-mode-vertical-lr-ref.html b/testing/web-platform/tests/html/semantics/forms/the-select-element/stylable-select/select-appearance-writing-mode-vertical-lr-ref.html
new file mode 100644
index 0000000000..8b7e6402fb
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-select-element/stylable-select/select-appearance-writing-mode-vertical-lr-ref.html
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<link rel=stylesheet href="resources/stylable-select-styles.css">
+
+<style>
+html {
+ writing-mode: vertical-lr;
+}
+</style>
+
+<div id=container class=stylable-select-container>
+ <button class=stylable-select-button popovertarget=popover id=button>
+ <span class=stylable-select-selectedoption>one</span>
+ <div class=stylable-select-button-icon></div>
+ </button>
+ <div id=popover popover=auto anchor=container class=stylable-select-datalist>
+ <div class=stylable-select-option>one</div>
+ <div class=stylable-select-option>two</div>
+ </div>
+</div>
+
+<script>
+document.getElementById('popover').showPopover();
+</script>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-select-element/stylable-select/select-appearance-writing-mode-vertical-lr.tentative.html b/testing/web-platform/tests/html/semantics/forms/the-select-element/stylable-select/select-appearance-writing-mode-vertical-lr.tentative.html
new file mode 100644
index 0000000000..2f8a6aa886
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-select-element/stylable-select/select-appearance-writing-mode-vertical-lr.tentative.html
@@ -0,0 +1,29 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<link rel=author href="mailto:jarhar@chromium.org">
+<link rel=help href="https://github.com/whatwg/html/issues/9799">
+<link rel=match href="select-appearance-writing-mode-vertical-lr-ref.html">
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
+
+<style>
+html {
+ writing-mode: vertical-lr;
+}
+select {
+ appearance: base-select;
+}
+</style>
+
+<select>
+ <option>one</option>
+ <option>two</option>
+</select>
+
+<script>
+(async () => {
+ await test_driver.bless();
+ document.querySelector('select').showPicker();
+ document.documentElement.classList.remove('reftest-wait');
+})();
+</script>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-select-element/stylable-select/select-appearance-writing-mode-vertical-rl-ref.html b/testing/web-platform/tests/html/semantics/forms/the-select-element/stylable-select/select-appearance-writing-mode-vertical-rl-ref.html
new file mode 100644
index 0000000000..158807ba58
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-select-element/stylable-select/select-appearance-writing-mode-vertical-rl-ref.html
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<link rel=stylesheet href="resources/stylable-select-styles.css">
+
+<style>
+html {
+ writing-mode: vertical-rl;
+}
+</style>
+
+<div id=container class=stylable-select-container>
+ <button class=stylable-select-button popovertarget=popover id=button>
+ <span class=stylable-select-selectedoption>one</span>
+ <div class=stylable-select-button-icon></div>
+ </button>
+ <div id=popover popover=auto anchor=container class=stylable-select-datalist>
+ <div class=stylable-select-option>one</div>
+ <div class=stylable-select-option>two</div>
+ </div>
+</div>
+
+<script>
+document.getElementById('popover').showPopover();
+</script>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-select-element/stylable-select/select-appearance-writing-mode-vertical-rl.tentative.html b/testing/web-platform/tests/html/semantics/forms/the-select-element/stylable-select/select-appearance-writing-mode-vertical-rl.tentative.html
new file mode 100644
index 0000000000..c2ea647be9
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-select-element/stylable-select/select-appearance-writing-mode-vertical-rl.tentative.html
@@ -0,0 +1,29 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<link rel=author href="mailto:jarhar@chromium.org">
+<link rel=help href="https://github.com/whatwg/html/issues/9799">
+<link rel=match href="select-appearance-writing-mode-vertical-rl-ref.html">
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
+
+<style>
+html {
+ writing-mode: vertical-rl;
+}
+select {
+ appearance: base-select;
+}
+</style>
+
+<select>
+ <option>one</option>
+ <option>two</option>
+</select>
+
+<script>
+(async () => {
+ await test_driver.bless();
+ document.querySelector('select').showPicker();
+ document.documentElement.classList.remove('reftest-wait');
+})();
+</script>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-select-element/stylable-select/select-child-button-and-datalist-invalidation.tentative.html b/testing/web-platform/tests/html/semantics/forms/the-select-element/stylable-select/select-child-button-and-datalist-invalidation.tentative.html
index b6d85ac90a..822a63e104 100644
--- a/testing/web-platform/tests/html/semantics/forms/the-select-element/stylable-select/select-child-button-and-datalist-invalidation.tentative.html
+++ b/testing/web-platform/tests/html/semantics/forms/the-select-element/stylable-select/select-child-button-and-datalist-invalidation.tentative.html
@@ -3,7 +3,6 @@
<link rel=author href="mailto:jarhar@chromium.org">
<link rel=help href="https://github.com/whatwg/html/issues/9799">
<link rel=match href="select-child-button-and-datalist-ref.html">
-<link rel=stylesheet href="resources/select-reset-non-interoperable-styles.css">
<style>
.blue {
diff --git a/testing/web-platform/tests/html/semantics/forms/the-select-element/stylable-select/select-child-button-and-datalist.tentative.html b/testing/web-platform/tests/html/semantics/forms/the-select-element/stylable-select/select-child-button-and-datalist.tentative.html
index 610861aad8..9b2f53df28 100644
--- a/testing/web-platform/tests/html/semantics/forms/the-select-element/stylable-select/select-child-button-and-datalist.tentative.html
+++ b/testing/web-platform/tests/html/semantics/forms/the-select-element/stylable-select/select-child-button-and-datalist.tentative.html
@@ -2,7 +2,6 @@
<link rel=author href="mailto:jarhar@chromium.org">
<link rel=help href="https://github.com/whatwg/html/issues/9799">
<link rel=match href="select-child-button-and-datalist-ref.html">
-<link rel=stylesheet href="resources/select-reset-non-interoperable-styles.css">
<style>
.blue {
diff --git a/testing/web-platform/tests/html/semantics/forms/the-select-element/stylable-select/select-datalist-popover-behavior.tentative.html b/testing/web-platform/tests/html/semantics/forms/the-select-element/stylable-select/select-datalist-popover-behavior.tentative.html
new file mode 100644
index 0000000000..caea2a2f8d
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-select-element/stylable-select/select-datalist-popover-behavior.tentative.html
@@ -0,0 +1,75 @@
+<!DOCTYPE html>
+<link rel=author href="mailto:jarhar@chromium.org">
+<link rel=help href="https://bugs.chromium.org/p/chromium/issues/detail?id=1422275">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
+<script src="/resources/testdriver-actions.js"></script>
+
+<select style="appearance:base-select">
+ <button type=popover>button</button>
+ <datalist>
+ <option class=one>one</option>
+ <option class=two>two</option>
+ </datalist>
+</select>
+
+<script>
+const select = document.querySelector('select');
+const datalist = document.querySelector('datalist');
+const firstOption = document.querySelector('option.one');
+const secondOption = document.querySelector('option.two');
+
+promise_test(async () => {
+ datalist.showPopover();
+ assert_true(datalist.matches(':popover-open'));
+ datalist.hidePopover();
+ assert_false(datalist.matches(':popover-open'));
+}, 'showPopover and hidePopover should work on the select datalist.');
+
+promise_test(async () => {
+ await test_driver.bless();
+ select.showPicker();
+ assert_true(datalist.matches(':popover-open'));
+ datalist.hidePopover();
+}, 'showPicker should show the select datalist.');
+
+promise_test(async () => {
+ datalist.addEventListener('beforetoggle', event => {
+ event.preventDefault();
+ }, {once: true});
+ await test_driver.bless();
+ select.showPicker();
+ assert_false(datalist.matches(':popover-open'));
+}, 'preventDefault on beforetoggle should prevent the datalist from showing.');
+
+promise_test(async () => {
+ select.remove();
+ assert_throws_dom('InvalidStateError', () => datalist.showPopover());
+ assert_false(datalist.matches(':popover-open'));
+ document.body.appendChild(select);
+}, 'showPopover on a disconnected datalist should throw an exception.');
+
+promise_test(async () => {
+ datalist.addEventListener('beforetoggle', event => {
+ select.remove();
+ }, {once: true});
+ await test_driver.bless();
+ select.showPicker();
+ assert_false(!!select.parentNode);
+ assert_false(datalist.matches(':popover-open'));
+ document.body.appendChild(select);
+}, 'Disconnecting while internally showing the datalist should not crash or show the popover.');
+
+promise_test(async () => {
+ datalist.showPopover();
+ datalist.addEventListener('beforetoggle', event => {
+ select.remove();
+ }, {once: true});
+ await test_driver.click(secondOption);
+ assert_false(!!select.parentNode);
+ assert_false(datalist.matches(':popover-open'));
+ document.body.appendChild(select);
+}, 'Disconnecting while internally hiding the datalist should not crash.');
+</script>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-select-element/stylable-select/select-keyboard-behavior.tentative.html b/testing/web-platform/tests/html/semantics/forms/the-select-element/stylable-select/select-keyboard-behavior.tentative.html
index 2fb11ba68b..8b06212169 100644
--- a/testing/web-platform/tests/html/semantics/forms/the-select-element/stylable-select/select-keyboard-behavior.tentative.html
+++ b/testing/web-platform/tests/html/semantics/forms/the-select-element/stylable-select/select-keyboard-behavior.tentative.html
@@ -1,4 +1,5 @@
<!DOCTYPE html>
+<meta name=timeout content=long>
<link rel=author href="mailto:jarhar@chromium.org">
<link rel=help href="https://bugs.chromium.org/p/chromium/issues/detail?id=1422275">
<link rel=help href="https://github.com/openui/open-ui/issues/433#issuecomment-1452461404">
@@ -68,6 +69,7 @@ for (const id of ['defaultbutton-defaultdatalist',
async function closeListbox() {
await test_driver.click(select);
+ await new Promise(requestAnimationFrame);
}
function addCloseCleanup(t) {
@@ -96,6 +98,7 @@ for (const id of ['defaultbutton-defaultdatalist',
assert_false(select.matches(':open'),
'The select should initially be closed.');
await test_driver.send_keys(document.activeElement, Space);
+ await new Promise(requestAnimationFrame);
assert_true(select.matches(':open'),
'The select should be open after pressing space.');
}, `${id}: When the listbox is closed, spacebar should open the listbox.`);
@@ -108,6 +111,7 @@ for (const id of ['defaultbutton-defaultdatalist',
'The select should initially be closed.');
await test_driver.send_keys(document.activeElement, ArrowLeft);
+ await new Promise(requestAnimationFrame);
assert_true(select.matches(':open'),
'Arrow left should open the listbox.');
assert_equals(select.value, 'two',
@@ -115,6 +119,7 @@ for (const id of ['defaultbutton-defaultdatalist',
await closeListbox();
await test_driver.send_keys(document.activeElement, ArrowUp);
+ await new Promise(requestAnimationFrame);
assert_true(select.matches(':open'),
'Arrow up should open the listbox.');
assert_equals(select.value, 'two',
@@ -122,6 +127,7 @@ for (const id of ['defaultbutton-defaultdatalist',
await closeListbox();
await test_driver.send_keys(document.activeElement, ArrowRight);
+ await new Promise(requestAnimationFrame);
assert_true(select.matches(':open'),
'Arrow right should open the listbox.');
assert_equals(select.value, 'two',
@@ -129,6 +135,7 @@ for (const id of ['defaultbutton-defaultdatalist',
await closeListbox();
await test_driver.send_keys(document.activeElement, ArrowDown);
+ await new Promise(requestAnimationFrame);
assert_true(select.matches(':open'),
'Arrow down should open the listbox.');
assert_equals(select.value, 'two',
@@ -147,6 +154,7 @@ for (const id of ['defaultbutton-defaultdatalist',
} else {
await test_driver.send_keys(select, Enter);
}
+ await new Promise(requestAnimationFrame);
assert_false(select.matches(':open'),
'Enter should not open the listbox when outside a form.');
@@ -161,6 +169,7 @@ for (const id of ['defaultbutton-defaultdatalist',
} else {
await test_driver.send_keys(select, Enter);
}
+ await new Promise(requestAnimationFrame);
assert_true(formWasSubmitted,
'Enter should submit the form when the listbox is closed.');
assert_false(select.matches(':open'),
@@ -175,30 +184,35 @@ for (const id of ['defaultbutton-defaultdatalist',
select.value = 'two';
await test_driver.click(select);
+ await new Promise(requestAnimationFrame);
assert_true(select.matches(':open'),
'The select should open when clicked.');
assert_equals(document.activeElement, optionTwo,
'The selected option should receive initial focus.');
await test_driver.send_keys(document.activeElement, ArrowDown);
+ await new Promise(requestAnimationFrame);
assert_equals(document.activeElement, optionThree,
'The next option should receive focus when the down arrow key is pressed.');
assert_equals(select.value, 'two',
'The selects value should not change when focusing another option.');
await test_driver.send_keys(document.activeElement, ArrowUp);
+ await new Promise(requestAnimationFrame);
assert_equals(document.activeElement, optionTwo,
'The previous option should receive focus when the up arrow key is pressed.');
assert_equals(select.value, 'two',
'The selects value should not change when focusing another option.');
await test_driver.send_keys(document.activeElement, ArrowUp);
+ await new Promise(requestAnimationFrame);
assert_equals(document.activeElement, optionOne,
'The first option should be selected.');
assert_equals(select.value, 'two',
'The selects value should not change when focusing another option.');
await test_driver.send_keys(document.activeElement, Enter);
+ await new Promise(requestAnimationFrame);
assert_false(select.matches(':open'),
'The listbox should be closed after pressing enter.');
assert_equals(select.value, 'one',
diff --git a/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-option-arbitrary-content-displayed.tentative.html b/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-option-arbitrary-content-displayed.tentative.html
index 2d51002fb2..8c620bacca 100644
--- a/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-option-arbitrary-content-displayed.tentative.html
+++ b/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-option-arbitrary-content-displayed.tentative.html
@@ -3,6 +3,8 @@
<title>HTMLSelectListElement Test: option arbitrary content displayed</title>
<link rel="author" title="Ionel Popescu" href="mailto:iopopesc@microsoft.com">
<link rel=match href="selectlist-option-arbitrary-content-displayed-ref.tentative.html">
+<!-- Tolerate slight differences in the shadow gradient. -->
+<meta name=fuzzy content="maxDifference=0-1;totalPixels=0-200">
<link rel="stylesheet" href="/fonts/ahem.css">
<script src="/resources/testdriver.js"></script>
<script src="/resources/testdriver-actions.js"></script>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-textarea-element/WEB_FEATURES.yml b/testing/web-platform/tests/html/semantics/forms/the-textarea-element/WEB_FEATURES.yml
new file mode 100644
index 0000000000..14479d4bb3
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-textarea-element/WEB_FEATURES.yml
@@ -0,0 +1,6 @@
+features:
+- name: constraint-validation
+ files:
+ - textarea-setcustomvalidity.html
+ - textarea-validity-clone.html
+ - textarea-validity-valueMissing-inside-datalist.html
diff --git a/testing/web-platform/tests/html/semantics/interactive-elements/the-details-element/WEB_FEATURES.yml b/testing/web-platform/tests/html/semantics/interactive-elements/the-details-element/WEB_FEATURES.yml
new file mode 100644
index 0000000000..be3924a26a
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/interactive-elements/the-details-element/WEB_FEATURES.yml
@@ -0,0 +1,4 @@
+features:
+- name: details-name
+ files:
+ - name-attribute.html
diff --git a/testing/web-platform/tests/html/semantics/invokers/interesttarget-anchor-event-dispatch.tentative.html b/testing/web-platform/tests/html/semantics/invokers/interesttarget-anchor-event-dispatch.tentative.html
new file mode 100644
index 0000000000..b5a481ae08
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/invokers/interesttarget-anchor-event-dispatch.tentative.html
@@ -0,0 +1,47 @@
+<!doctype html>
+<meta charset="utf-8" />
+<meta name="author" title="Keith Cirkel" href="mailto:keithamus@github.com" />
+<meta name="author" title="Luke Warlow" href="mailto:lwarlow@igalia.com" />
+<link rel="help" href="https://open-ui.org/components/invokers.explainer/" />
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-actions.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
+<script src="resources/invoker-utils.js"></script>
+
+<div id="interestee"></div>
+<a href="/" id="interestanchor" interesttarget="interestee">Anchor</a>
+<button id="otherbutton">Other Button</button>
+
+<script>
+ promise_test(async function (t) {
+ t.add_cleanup(() => otherbutton.focus());
+ let event = null;
+ interestee.addEventListener("interest", (e) => (event = e), { once: true });
+ interestanchor.focus();
+ assert_true(event instanceof InterestEvent, "event is InterestEvent");
+ assert_equals(event.type, "interest", "type");
+ assert_equals(event.bubbles, false, "bubbles");
+ assert_equals(event.composed, true, "composed");
+ assert_equals(event.isTrusted, true, "isTrusted");
+ assert_equals(event.action, "", "action");
+ assert_equals(event.target, interestee, "target");
+ assert_equals(event.invoker, interestanchor, "invoker");
+ }, "InterestEvent dispatches on anchor focus");
+
+ promise_test(async function (t) {
+ t.add_cleanup(() => otherbutton.focus());
+ let event = null;
+ interestee.addEventListener("interest", (e) => (event = e), { once: true });
+ await hoverOver(interestanchor);
+ assert_true(event instanceof InterestEvent, "event is InterestEvent");
+ assert_equals(event.type, "interest", "type");
+ assert_equals(event.bubbles, false, "bubbles");
+ assert_equals(event.composed, true, "composed");
+ assert_equals(event.isTrusted, true, "isTrusted");
+ assert_equals(event.action, "", "action");
+ assert_equals(event.target, interestee, "target");
+ assert_equals(event.invoker, interestanchor, "invoker");
+ }, "InterestEvent dispatches on anchor hover");
+</script>
diff --git a/testing/web-platform/tests/html/semantics/invokers/interesttarget-area-event-dispatch.tentative.html b/testing/web-platform/tests/html/semantics/invokers/interesttarget-area-event-dispatch.tentative.html
new file mode 100644
index 0000000000..358acbb73a
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/invokers/interesttarget-area-event-dispatch.tentative.html
@@ -0,0 +1,50 @@
+<!doctype html>
+<meta charset="utf-8" />
+<meta name="author" title="Keith Cirkel" href="mailto:keithamus@github.com" />
+<meta name="author" title="Luke Warlow" href="mailto:lwarlow@igalia.com" />
+<link rel="help" href="https://open-ui.org/components/invokers.explainer/" />
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-actions.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
+<script src="resources/invoker-utils.js"></script>
+
+<div id="interestee"></div>
+<map id="map">
+ <area href="/" shape="default" id="interestarea" interesttarget="interestee">
+</map>
+<img src="/images/blue.png" usemap="#map">
+<button id="otherbutton">Other Button</button>
+
+<script>
+ promise_test(async function (t) {
+ t.add_cleanup(() => otherbutton.focus());
+ let event = null;
+ interestee.addEventListener("interest", (e) => (event = e), { once: true });
+ interestarea.focus();
+ assert_true(event instanceof InterestEvent, "event is InterestEvent");
+ assert_equals(event.type, "interest", "type");
+ assert_equals(event.bubbles, false, "bubbles");
+ assert_equals(event.composed, true, "composed");
+ assert_equals(event.isTrusted, true, "isTrusted");
+ assert_equals(event.action, "", "action");
+ assert_equals(event.target, interestee, "target");
+ assert_equals(event.invoker, interestarea, "invoker");
+ }, "InterestEvent dispatches on area focus");
+
+ promise_test(async function (t) {
+ t.add_cleanup(() => otherbutton.focus());
+ let event = null;
+ interestee.addEventListener("interest", (e) => (event = e), { once: true });
+ await hoverOver(interestarea);
+ assert_true(event instanceof InterestEvent, "event is InterestEvent");
+ assert_equals(event.type, "interest", "type");
+ assert_equals(event.bubbles, false, "bubbles");
+ assert_equals(event.composed, true, "composed");
+ assert_equals(event.isTrusted, true, "isTrusted");
+ assert_equals(event.action, "", "action");
+ assert_equals(event.target, interestee, "target");
+ assert_equals(event.invoker, interestarea, "invoker");
+ }, "InterestEvent dispatches on area hover");
+</script>
diff --git a/testing/web-platform/tests/html/semantics/invokers/interesttarget-button-event-dispatch.tentative.html b/testing/web-platform/tests/html/semantics/invokers/interesttarget-button-event-dispatch.tentative.html
index 7fdfdfaa70..69126dbe14 100644
--- a/testing/web-platform/tests/html/semantics/invokers/interesttarget-button-event-dispatch.tentative.html
+++ b/testing/web-platform/tests/html/semantics/invokers/interesttarget-button-event-dispatch.tentative.html
@@ -12,7 +12,6 @@
<div id="interestee"></div>
<button id="interestbutton" interesttarget="interestee">Button</button>
-<a href="/" id="interestanchor" interesttarget="interestee">Anchor</a>
<button id="otherbutton">Other Button</button>
<script>
@@ -50,36 +49,6 @@
t.add_cleanup(() => otherbutton.focus());
let event = null;
interestee.addEventListener("interest", (e) => (event = e), { once: true });
- interestanchor.focus();
- assert_true(event instanceof InterestEvent, "event is InterestEvent");
- assert_equals(event.type, "interest", "type");
- assert_equals(event.bubbles, false, "bubbles");
- assert_equals(event.composed, true, "composed");
- assert_equals(event.isTrusted, true, "isTrusted");
- assert_equals(event.action, "", "action");
- assert_equals(event.target, interestee, "target");
- assert_equals(event.invoker, interestanchor, "invoker");
- }, "InterestEvent dispatches on anchor focus");
-
- promise_test(async function (t) {
- t.add_cleanup(() => otherbutton.focus());
- let event = null;
- interestee.addEventListener("interest", (e) => (event = e), { once: true });
- await hoverOver(interestanchor);
- assert_true(event instanceof InterestEvent, "event is InterestEvent");
- assert_equals(event.type, "interest", "type");
- assert_equals(event.bubbles, false, "bubbles");
- assert_equals(event.composed, true, "composed");
- assert_equals(event.isTrusted, true, "isTrusted");
- assert_equals(event.action, "", "action");
- assert_equals(event.target, interestee, "target");
- assert_equals(event.invoker, interestanchor, "invoker");
- }, "InterestEvent dispatches on anchor hover");
-
- promise_test(async function (t) {
- t.add_cleanup(() => otherbutton.focus());
- let event = null;
- interestee.addEventListener("interest", (e) => (event = e), { once: true });
interestbutton.interestAction = "fooBar";
interestbutton.focus();
assert_true(event instanceof InterestEvent, "event is InterestEvent");
diff --git a/testing/web-platform/tests/html/semantics/invokers/interesttarget-svg-a-event-dispatch.tentative.html b/testing/web-platform/tests/html/semantics/invokers/interesttarget-svg-a-event-dispatch.tentative.html
new file mode 100644
index 0000000000..7fb4b1c19d
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/invokers/interesttarget-svg-a-event-dispatch.tentative.html
@@ -0,0 +1,51 @@
+<!doctype html>
+<meta charset="utf-8" />
+<meta name="author" title="Keith Cirkel" href="mailto:keithamus@github.com" />
+<meta name="author" title="Luke Warlow" href="mailto:lwarlow@igalia.com" />
+<link rel="help" href="https://open-ui.org/components/invokers.explainer/" />
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-actions.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
+<script src="resources/invoker-utils.js"></script>
+
+<div id="interestee"></div>
+<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg">
+ <a href="/" id="interestsvga" interesttarget="interestee">
+ <text x="50" y="90">SVG A</text>
+ </a>
+</svg>
+<button id="otherbutton">Other Button</button>
+
+<script>
+ promise_test(async function (t) {
+ t.add_cleanup(() => otherbutton.focus());
+ let event = null;
+ interestee.addEventListener("interest", (e) => (event = e), { once: true });
+ interestsvga.focus();
+ assert_true(event instanceof InterestEvent, "event is InterestEvent");
+ assert_equals(event.type, "interest", "type");
+ assert_equals(event.bubbles, false, "bubbles");
+ assert_equals(event.composed, true, "composed");
+ assert_equals(event.isTrusted, true, "isTrusted");
+ assert_equals(event.action, "", "action");
+ assert_equals(event.target, interestee, "target");
+ assert_equals(event.invoker, interestsvga, "invoker");
+ }, "InterestEvent dispatches on svg a focus");
+
+ promise_test(async function (t) {
+ t.add_cleanup(() => otherbutton.focus());
+ let event = null;
+ interestee.addEventListener("interest", (e) => (event = e), { once: true });
+ await hoverOver(interestsvga);
+ assert_true(event instanceof InterestEvent, "event is InterestEvent");
+ assert_equals(event.type, "interest", "type");
+ assert_equals(event.bubbles, false, "bubbles");
+ assert_equals(event.composed, true, "composed");
+ assert_equals(event.isTrusted, true, "isTrusted");
+ assert_equals(event.action, "", "action");
+ assert_equals(event.target, interestee, "target");
+ assert_equals(event.invoker, interestsvga, "invoker");
+ }, "InterestEvent dispatches on svg a hover");
+</script>
diff --git a/testing/web-platform/tests/html/semantics/invokers/invoketarget-on-input-number.tentative.html b/testing/web-platform/tests/html/semantics/invokers/invoketarget-on-input-number.tentative.html
new file mode 100644
index 0000000000..b06053b9f1
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/invokers/invoketarget-on-input-number.tentative.html
@@ -0,0 +1,78 @@
+<!doctype html>
+<meta charset="utf-8" />
+<meta name="author" title="Luke Warlow" href="mailto:lwarlow@igalia.com" />
+<link rel="help" href="https://open-ui.org/components/invokers.explainer/" />
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-actions.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
+<script src="resources/invoker-utils.js"></script>
+
+<input type="number" id="invokee" value="0">
+<button id="invokerbutton" invoketarget="invokee"></button>
+
+<script>
+ function reset() {
+ invokee.value = 0;
+ invokerbutton.removeAttribute('invokeaction');
+ }
+
+ // stepUp
+
+ promise_test(async function (t) {
+ t.add_cleanup(reset);
+ assert_equals(invokee.valueAsNumber, 0);
+ invokerbutton.setAttribute("invokeaction", "stepup");
+ await clickOn(invokerbutton);
+ assert_equals(invokee.valueAsNumber, 1);
+ }, "invoking number input with stepup action increments value");
+
+ promise_test(async function (t) {
+ t.add_cleanup(reset);
+ assert_equals(invokee.valueAsNumber, 0);
+ invokerbutton.setAttribute("invokeaction", "sTePuP");
+ await clickOn(invokerbutton);
+ assert_equals(invokee.valueAsNumber, 1);
+ }, "invoking number input with stepup action (case-insensitive) increments value");
+
+ promise_test(async function (t) {
+ t.add_cleanup(reset);
+ assert_equals(invokee.valueAsNumber, 0);
+ invokerbutton.setAttribute("invokeaction", "stepup");
+ invokee.addEventListener("invoke", (e) => e.preventDefault(), {
+ once: true,
+ });
+ await clickOn(invokerbutton);
+ assert_equals(invokee.valueAsNumber, 0);
+ }, "invoking number input with stepup action and preventDefault does not increment value");
+
+ // stepDown
+
+ promise_test(async function (t) {
+ t.add_cleanup(reset);
+ assert_equals(invokee.valueAsNumber, 0);
+ invokerbutton.setAttribute("invokeaction", "stepdown");
+ await clickOn(invokerbutton);
+ assert_equals(invokee.valueAsNumber, -1);
+ }, "invoking number input with stepdown action decrements value");
+
+ promise_test(async function (t) {
+ t.add_cleanup(reset);
+ assert_equals(invokee.valueAsNumber, 0);
+ invokerbutton.setAttribute("invokeaction", "sTePdOwN");
+ await clickOn(invokerbutton);
+ assert_equals(invokee.valueAsNumber, -1);
+ }, "invoking number input with stepdown action (case-insensitive) decrements value");
+
+ promise_test(async function (t) {
+ t.add_cleanup(reset);
+ assert_equals(invokee.valueAsNumber, 0);
+ invokerbutton.setAttribute("invokeaction", "stepdown");
+ invokee.addEventListener("invoke", (e) => e.preventDefault(), {
+ once: true,
+ });
+ await clickOn(invokerbutton);
+ assert_equals(invokee.valueAsNumber, 0);
+ }, "invoking number input with stepdown action and preventDefault does not decrement value");
+</script>
diff --git a/testing/web-platform/tests/html/semantics/permission-element/bounded-css-properties-reference-expected.html b/testing/web-platform/tests/html/semantics/permission-element/bounded-css-properties-reftest-ref.html
index c62ff5b24d..c62ff5b24d 100644
--- a/testing/web-platform/tests/html/semantics/permission-element/bounded-css-properties-reference-expected.html
+++ b/testing/web-platform/tests/html/semantics/permission-element/bounded-css-properties-reftest-ref.html
diff --git a/testing/web-platform/tests/html/semantics/permission-element/bounded-css-properties-reference.tentative.html b/testing/web-platform/tests/html/semantics/permission-element/bounded-css-properties-reftest.tentative.html
index b8337ab87d..ad6986f52b 100644
--- a/testing/web-platform/tests/html/semantics/permission-element/bounded-css-properties-reference.tentative.html
+++ b/testing/web-platform/tests/html/semantics/permission-element/bounded-css-properties-reftest.tentative.html
@@ -1,6 +1,6 @@
<!DOCTYPE html>
<meta charset=utf-8>
-<link rel="match" href="bounded-css-properties-reference-expected.html">
+<link rel="match" href="bounded-css-properties-reftest-ref.html">
<link rel="help" href="https://github.com/WICG/PEPC/blob/main/explainer.md#locking-the-pepc-style">
<body>
<div>
diff --git a/testing/web-platform/tests/html/semantics/permission-element/bounded-sizes-reftest-ref.html b/testing/web-platform/tests/html/semantics/permission-element/bounded-sizes-reftest-ref.html
new file mode 100644
index 0000000000..b186dd6445
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/permission-element/bounded-sizes-reftest-ref.html
@@ -0,0 +1,56 @@
+<!DOCTYPE html>
+<html>
+<meta charset=utf-8>
+<body>
+ <div>
+ The permission element should have some limits for the min/max-width/height:
+ <ul>
+ <li>min-width should be sufficient to fit the element text (depends on user agent implementation)</li>
+ <li>max-width should be at most 3x min-width</li>
+ <li>min-height should be sufficient to fit the element text (1em)</li>
+ <li>max-height should be at most 3x min-height</li>
+ <li>padding-left/top only work with width/height: auto and are at most 5em/1em</li>
+ <li>padding-right/bottom are copied over from padding-left/top in this case</li>
+ </ul>
+ </div>
+
+ <style>
+ #id1 {
+ font-size: 10px;
+ height: 10px;
+ /* width set via JS */
+ }
+ #id2 {
+ font-size: 10px;
+ height: 30px;
+ /* width set via JS */
+ }
+ #id3 {
+ font-size: 10px;
+ height: 30px;
+ color:black;
+ background-color: black;
+
+ /* Used to compute width which will then have the padding
+ artificially added in JS */
+ width: fit-content;
+ }
+ </style>
+
+ <div><permission id="id1" type="geolocation"></div>
+ <div><permission id="id2" type="camera"></div>
+ <div><permission id="id3" type="microphone"></div>
+
+<script>
+ let el = document.getElementById("id1");
+ el.style.width = getComputedStyle(el).minWidth;
+
+ el = document.getElementById("id2");
+ el.style.width = getComputedStyle(el).maxWidth;
+
+ el = document.getElementById("id3");
+ let w = getComputedStyle(el).width;
+ el.style.width = `calc(${w} + 100px)`; // 100px is 2 * 5em;
+</script>
+</body>
+</html> \ No newline at end of file
diff --git a/testing/web-platform/tests/html/semantics/permission-element/bounded-sizes-reftest.tentative.html b/testing/web-platform/tests/html/semantics/permission-element/bounded-sizes-reftest.tentative.html
new file mode 100644
index 0000000000..45ffb633c3
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/permission-element/bounded-sizes-reftest.tentative.html
@@ -0,0 +1,68 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<link rel="match" href="bounded-sizes-reftest-ref.html">
+<link rel="help" href="https://github.com/WICG/PEPC/blob/main/explainer.md#locking-the-pepc-style">
+<body>
+ <div>
+ The permission element should have some limits for the min/max-width/height:
+ <ul>
+ <li>min-width should be sufficient to fit the element text (depends on user agent implementation)</li>
+ <li>max-width should be at most 3x min-width</li>
+ <li>min-height should be sufficient to fit the element text (1em)</li>
+ <li>max-height should be at most 3x min-height</li>
+ <li>padding-left/top only work with width/height: auto and are at most 5em/1em</li>
+ <li>padding-right/bottom are copied over from padding-left/top in this case</li>
+ </ul>
+ </div>
+
+<style>
+ #id1 {
+ font-size: 10px;
+ min-height: 1px;
+ max-height: 100px;
+
+ /* These values are extreme enough that they should be out of bounds for any implementation */
+ min-width: 10px;
+ max-width: 1000px;
+
+ /* This element will be as tiny as possible */
+ width: 1px;
+ height: 1px;
+ }
+ #id2 {
+ font-size: 10px;
+ min-height: 1px;
+ max-height: 100px;
+
+ /* These values are extreme enough that they should be out of bounds for any implementation */
+ min-width: 10px;
+ max-width: 1000px;
+
+ /* This element will be as large as possible */
+ width: 1000px;
+ height: 1000px;
+ }
+ #id3 {
+ font-size: 10px;
+ width: auto;
+ height: auto;
+
+ /* There is a slight misalignment of the text (by 1px) when using
+ padding vs using width/height. Since this test's purpose is to
+ check that the bounds are identical, the color and background-color
+ are set to the same value to cover the slight text misalignment */
+ color:black;
+ background-color: black;
+
+ /* Only padding-top and padding-left are taken into account */
+ padding-top: 1000px;
+ padding-left: 1000px;
+ padding-bottom: 1px;
+ padding-right: 1px;
+ }
+</style>
+
+<div><permission id="id1" type="geolocation"></div>
+<div><permission id="id2" type="camera"></div>
+<div><permission id="id3" type="microphone"></div>
+</body> \ No newline at end of file
diff --git a/testing/web-platform/tests/html/semantics/permission-element/bounded-sizes.tentative.html b/testing/web-platform/tests/html/semantics/permission-element/bounded-sizes.tentative.html
new file mode 100644
index 0000000000..2010cd0a54
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/permission-element/bounded-sizes.tentative.html
@@ -0,0 +1,75 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<link rel="help" href="https://github.com/WICG/PEPC/blob/main/explainer.md#locking-the-pepc-style">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<body>
+<!--The permission element should have some limits for the min/max-width/height:
+ * min-width should be sufficient to fit the element text (depends on user agent implementation)
+ * max-width should be at most 3x min-width
+ * min-height should be sufficient to fit the element text (1em)
+ * max-height should be at most 3x min-height
+-->
+<style>
+ #id1 {
+ font-size: 10px;
+ width: auto;
+ height: auto;
+
+ min-height: 1px;
+ max-height: 100px;
+
+ padding-top: 12px;
+ padding-left: 60px;
+ padding-bottom: 1000px;
+ padding-right: 1000px;
+
+ /* These values are extreme enough that they should be out of bounds for any implementation */
+ min-width: 10px;
+ max-width: 1000px;
+ }
+ #id2 {
+ font-size: 10px;
+ width: auto;
+ height: auto;
+
+ min-height: 11px;
+ max-height: 29px;
+
+ padding-top: 5px;
+ padding-left: 45px;
+ padding-bottom: 6px;
+ padding-right: 46px;
+ }
+</style>
+
+
+<permission id="id1" type="geolocation">
+<permission id="id2" type="camera">
+
+<script>
+ test(function(){
+ let el_outside_bounds = document.getElementById("id1");
+ let min_height = getComputedStyle(el_outside_bounds).minHeight;
+ let max_height = getComputedStyle(el_outside_bounds).maxHeight;
+ assert_true(min_height === "calc(10px)" || min_height === "10px", "min-height");
+ assert_true(max_height === "calc(30px)" || max_height === "30px", "max-height");
+ assert_not_equals(getComputedStyle(el_outside_bounds).minWidth, "10px", "min-width");
+ assert_not_equals(getComputedStyle(el_outside_bounds).maxWidth, "1000px", "max-width");
+ assert_equals(getComputedStyle(el_outside_bounds).paddingLeft, "50px", "padding-left");
+ assert_equals(getComputedStyle(el_outside_bounds).paddingRight, "50px", "padding-right");
+ assert_equals(getComputedStyle(el_outside_bounds).paddingTop, "10px", "padding-top");
+ assert_equals(getComputedStyle(el_outside_bounds).paddingBottom, "10px", "padding-bottom");
+ }, "Properties with out-of-bounds values should be corrected");
+
+ test(function(){
+ let el_inside_bounds = document.getElementById("id2");
+ assert_equals(getComputedStyle(el_inside_bounds).minHeight, "calc(11px)", "min-height");
+ assert_equals(getComputedStyle(el_inside_bounds).maxHeight, "calc(29px)", "max-height");
+ assert_equals(getComputedStyle(el_inside_bounds).paddingLeft, "45px", "padding-left");
+ assert_equals(getComputedStyle(el_inside_bounds).paddingRight, "45px", "padding-right");
+ assert_equals(getComputedStyle(el_inside_bounds).paddingTop, "5px", "padding-top");
+ assert_equals(getComputedStyle(el_inside_bounds).paddingBottom, "5px", "padding-bottom");
+ }, "Properties with values in bounds should not be modified");
+</script>
+</body> \ No newline at end of file
diff --git a/testing/web-platform/tests/html/semantics/permission-element/display-css-property-reference-expected.html b/testing/web-platform/tests/html/semantics/permission-element/display-css-property-reftest-ref.html
index 6a04c94c03..6a04c94c03 100644
--- a/testing/web-platform/tests/html/semantics/permission-element/display-css-property-reference-expected.html
+++ b/testing/web-platform/tests/html/semantics/permission-element/display-css-property-reftest-ref.html
diff --git a/testing/web-platform/tests/html/semantics/permission-element/display-css-property-reference.tentative.html b/testing/web-platform/tests/html/semantics/permission-element/display-css-property-reftest.tentative.html
index 973a76d723..e83786373d 100644
--- a/testing/web-platform/tests/html/semantics/permission-element/display-css-property-reference.tentative.html
+++ b/testing/web-platform/tests/html/semantics/permission-element/display-css-property-reftest.tentative.html
@@ -1,6 +1,6 @@
<!DOCTYPE html>
<meta charset=utf-8>
-<link rel="match" href="display-css-property-reference-expected.html">
+<link rel="match" href="display-css-property-reftest-ref.html">
<link rel="help" href="https://github.com/WICG/PEPC/blob/main/explainer.md#locking-the-pepc-style">
<body>
<div>
diff --git a/testing/web-platform/tests/html/semantics/popovers/popover-anchor-change-display.tentative.html b/testing/web-platform/tests/html/semantics/popovers/popover-anchor-change-display.tentative.html
index 435929a6c1..4312a156ce 100644
--- a/testing/web-platform/tests/html/semantics/popovers/popover-anchor-change-display.tentative.html
+++ b/testing/web-platform/tests/html/semantics/popovers/popover-anchor-change-display.tentative.html
@@ -42,6 +42,7 @@ window.addEventListener('load', runTest);
background: orange;
}
[popover] {
+ inset: auto;
background: lime;
padding:0;
border:0;
diff --git a/testing/web-platform/tests/html/semantics/popovers/popover-anchor-display-none.tentative.html b/testing/web-platform/tests/html/semantics/popovers/popover-anchor-display-none.tentative.html
index 55a11fafdb..8db022b126 100644
--- a/testing/web-platform/tests/html/semantics/popovers/popover-anchor-display-none.tentative.html
+++ b/testing/web-platform/tests/html/semantics/popovers/popover-anchor-display-none.tentative.html
@@ -15,6 +15,7 @@
display: none;
}
[popover] {
+ inset: auto;
background: lime;
padding: 0;
border: 0;
diff --git a/testing/web-platform/tests/html/semantics/popovers/popover-anchor-display.tentative.html b/testing/web-platform/tests/html/semantics/popovers/popover-anchor-display.tentative.html
index bddc44006d..a713540094 100644
--- a/testing/web-platform/tests/html/semantics/popovers/popover-anchor-display.tentative.html
+++ b/testing/web-platform/tests/html/semantics/popovers/popover-anchor-display.tentative.html
@@ -61,6 +61,7 @@ showDefaultopenPopoversOnLoad();
background: orange;
}
[popover] {
+ inset: auto;
background: lime;
padding:0;
border:0;
diff --git a/testing/web-platform/tests/html/semantics/popovers/popover-anchor-scroll-display.tentative.html b/testing/web-platform/tests/html/semantics/popovers/popover-anchor-scroll-display.tentative.html
index 2c6b0bafb9..a301032a5b 100644
--- a/testing/web-platform/tests/html/semantics/popovers/popover-anchor-scroll-display.tentative.html
+++ b/testing/web-platform/tests/html/semantics/popovers/popover-anchor-scroll-display.tentative.html
@@ -40,6 +40,7 @@
background: orange;
}
[popover] {
+ inset: auto;
background: lime;
padding:0;
border:0;
diff --git a/testing/web-platform/tests/html/semantics/popovers/popover-anchor-transition.tentative.tentative.html b/testing/web-platform/tests/html/semantics/popovers/popover-anchor-transition.tentative.tentative.html
index ae2a3a8e41..f6220f3c76 100644
--- a/testing/web-platform/tests/html/semantics/popovers/popover-anchor-transition.tentative.tentative.html
+++ b/testing/web-platform/tests/html/semantics/popovers/popover-anchor-transition.tentative.tentative.html
@@ -13,6 +13,7 @@ body {
}
#target {
+ inset: auto;
transition: display 2s;
}
</style>
diff --git a/testing/web-platform/tests/html/semantics/popovers/popover-focus-2.html b/testing/web-platform/tests/html/semantics/popovers/popover-focus-2.html
index 892e5fd68f..8f24ace919 100644
--- a/testing/web-platform/tests/html/semantics/popovers/popover-focus-2.html
+++ b/testing/web-platform/tests/html/semantics/popovers/popover-focus-2.html
@@ -80,7 +80,7 @@ promise_test(async t => {
assert_equals(document.activeElement,invoker2,'Focus should move within popover');
await sendShiftTab();
await sendShiftTab();
- assert_equals(document.activeElement, button1 ,'Focus should not move back to invoker as it is non-focusable');
+ assert_equals(document.activeElement,invoker0,'Focus should not move back to invoker as it is non-focusable');
// Reset invoker1 to focusable.
invoker1.disabled = false;
await verifyFocusOrder([button1, button2, invoker0, invoker1, inside_popover1, invoker2, inside_popover2, button3, button4],'set 1');
diff --git a/testing/web-platform/tests/html/semantics/popovers/popover-hover-crash-hang.tentative.html b/testing/web-platform/tests/html/semantics/popovers/popover-hover-crash-hang.tentative.html
new file mode 100644
index 0000000000..60309398db
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/popovers/popover-hover-crash-hang.tentative.html
@@ -0,0 +1,34 @@
+<!DOCTYPE html>
+<meta charset="utf-8" />
+<title>Crash/hang test for popover hover behavior</title>
+<link rel="author" href="mailto:masonf@chromium.org">
+<link rel=help href="https://open-ui.org/components/popover-hint.research.explainer/">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-actions.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
+<script src="resources/popover-utils.js"></script>
+
+<div id=menu popover=manual>
+ Popover
+ <button popovertarget="submenu"><span id=button>Button</span>
+ <div id=submenu popover=manual>Button-contained popover</div>
+ </button>
+</div>
+<button id=unrelated>Unrelated</button>
+
+<script>
+ promise_test(async (t) => {
+ menu.showPopover();
+ assert_true(menu.matches(':popover-open'));
+ await mouseHover(button,100);
+ button.click();
+ assert_true(menu.matches(':popover-open'));
+ assert_true(submenu.matches(':popover-open'));
+ await mouseHover(submenu,100);
+ await mouseHover(unrelated,100);
+ assert_true(submenu.matches(':popover-open'));
+ // This test passes if nothing crashes/hangs.
+ },'crash test');
+</script>
diff --git a/testing/web-platform/tests/html/semantics/popovers/popover-light-dismiss-scroll-within.html b/testing/web-platform/tests/html/semantics/popovers/popover-light-dismiss-scroll-within.html
new file mode 100644
index 0000000000..2329aea201
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/popovers/popover-light-dismiss-scroll-within.html
@@ -0,0 +1,52 @@
+<!DOCTYPE html>
+<meta charset="utf-8" />
+<title>Popover light dismiss behavior when scrolled within</title>
+<meta name="timeout" content="long">
+<link rel="author" href="mailto:masonf@chromium.org">
+<link rel=help href="https://open-ui.org/components/popover.research.explainer">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-actions.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
+<script src="resources/popover-utils.js"></script>
+
+<style>
+ [popover] {
+ /* Position most popovers at the bottom-right, out of the way */
+ inset:auto;
+ bottom:0;
+ right:0;
+ }
+ [popover]::backdrop {
+ /* This should *not* affect anything: */
+ pointer-events: auto;
+ }
+</style>
+
+<div popover id=p>Inside popover
+ <div style="height:2000px;background:lightgreen"></div>
+ Bottom of popover6
+</div>
+<button popovertarget=p>Popover</button>
+<style>
+ #p6 {
+ width: 300px;
+ height: 300px;
+ overflow-y: scroll;
+ }
+</style>
+<script>
+ const popover = document.querySelector('#p');
+ promise_test(async () => {
+ popover.showPopover();
+ assert_equals(popover.scrollTop,0,'popover should start non-scrolled');
+ await new test_driver.Actions()
+ .scroll(0, 0, 0, 50, {origin: popover})
+ .send();
+ await waitForRender();
+ assert_true(popover.matches(':popover-open'),'popover should stay open');
+ assert_equals(popover.scrollTop,50,'popover should be scrolled');
+ popover.hidePopover();
+ },'Scrolling within a popover should not close the popover');
+</script>
diff --git a/testing/web-platform/tests/html/semantics/popovers/popover-light-dismiss.html b/testing/web-platform/tests/html/semantics/popovers/popover-light-dismiss.html
index 45db242e91..78b8674513 100644
--- a/testing/web-platform/tests/html/semantics/popovers/popover-light-dismiss.html
+++ b/testing/web-platform/tests/html/semantics/popovers/popover-light-dismiss.html
@@ -303,33 +303,6 @@
},'An invoking element that was not used to invoke the popover is not part of the ancestor chain');
</script>
-<div popover id=p6>Inside popover 6
- <div style="height:2000px;background:lightgreen"></div>
- Bottom of popover6
-</div>
-<button popovertarget=p6>Popover 6</button>
-<style>
- #p6 {
- width: 300px;
- height: 300px;
- overflow-y: scroll;
- }
-</style>
-<script>
- const popover6 = document.querySelector('#p6');
- promise_test(async () => {
- popover6.showPopover();
- assert_equals(popover6.scrollTop,0,'popover6 should start non-scrolled');
- await new test_driver.Actions()
- .scroll(0, 0, 0, 50, {origin: popover6})
- .send();
- await waitForRender();
- assert_true(popover6.matches(':popover-open'),'popover6 should stay open');
- assert_equals(popover6.scrollTop,50,'popover6 should be scrolled');
- popover6.hidePopover();
- },'Scrolling within a popover should not close the popover');
-</script>
-
<my-element id="myElement">
<template shadowrootmode="open">
<button id=b7 popovertarget=p7 popovertargetaction=show tabindex="0">Popover7</button>
@@ -602,18 +575,26 @@ promise_test(async () => {
p29.showPopover();
assert_true(p29.matches(':popover-open'),'showing');
let actions = new test_driver.Actions();
- await actions.pointerMove(0,0,{origin: b29})
+ // Using the iframe's contentDocument as the origin would throw an error, so
+ // we are using iframe29 as the origin instead.
+ const iframe_box = iframe29.getBoundingClientRect();
+
+ await actions
+ .pointerMove(1,1,{origin: b29})
.pointerDown({button: actions.ButtonType.LEFT})
+ .pointerMove(iframe_box.width / 2, iframe_box.height / 2, {origin: iframe29})
+ .pointerUp({button: actions.ButtonType.LEFT})
.send();
- await waitForRender();
- assert_true(p29.matches(':popover-open'),'showing after pointerdown');
+ assert_true(p29.matches(':popover-open'), 'popover should be open after pointerUp in iframe.');
actions = new test_driver.Actions();
- await actions.pointerMove(0,0,{origin: iframe29.contentDocument.body})
+ await actions
+ .pointerMove(iframe_box.width / 2, iframe_box.height / 2, {origin: iframe29})
+ .pointerDown({button: actions.ButtonType.LEFT})
+ .pointerMove(1,1,{origin: b29})
.pointerUp({button: actions.ButtonType.LEFT})
.send();
- await waitForRender();
- assert_true(p29.matches(':popover-open'),'showing after pointerup');
+ assert_true(p29.matches(':popover-open'), 'popover should be open after pointerUp on main frame button.');
},`Pointer down in one document and pointer up in another document shouldn't dismiss popover`);
</script>
@@ -626,13 +607,10 @@ promise_test(async () => {
p30.showPopover();
assert_true(p30.matches(':popover-open'),'showing');
let actions = new test_driver.Actions();
- await actions.pointerMove(0,0,{origin: b30})
+ await actions
+ .pointerMove(2,2,{origin: b30})
.pointerDown({button: actions.ButtonType.LEFT})
- .send();
- await waitForRender();
- assert_true(p30.matches(':popover-open'),'showing after pointerdown');
- actions = new test_driver.Actions();
- await actions.pointerMove(0,0,{origin: b30b})
+ .pointerMove(2,2,{origin: b30b})
.pointerUp({button: actions.ButtonType.LEFT})
.send();
await waitForRender();
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/microtasks/basic.any.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/microtasks/basic.any.js
index 82cb3b215d..4876e82b0d 100644
--- a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/microtasks/basic.any.js
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/microtasks/basic.any.js
@@ -25,8 +25,8 @@ promise_test(async t => {
// Use Date.now() to ensure that the module is not in the module map
const specifier = "./empty-module.js?" + Date.now();
- const getCount = ticker(1e7);
+ const getCount = ticker(1e6);
await import(specifier);
- assert_equals(getCount(), 1e7);
+ assert_equals(getCount(), 1e6);
}, "import() should drain the microtask queue when fetching a new module");
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/inline-async-inserted-execorder.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/inline-async-inserted-execorder.html
new file mode 100644
index 0000000000..0f51fd318b
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/inline-async-inserted-execorder.html
@@ -0,0 +1,70 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>Inline async="" module scripts execute or throw parse errors asynchronously</title>
+<link rel="help" href="https://github.com/whatwg/html/issues/9864">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<body>
+<script>
+"use strict";
+setup({ allow_uncaught_exception: true });
+
+promise_test(async t => {
+ window.log = ["before any script execution"];
+
+ window.addEventListener("error", ev => {
+ window.log.push("error event on Window");
+ });
+
+ const noErrorScript = document.createElement("script");
+ noErrorScript.type = "module";
+ noErrorScript.async = true;
+ noErrorScript.textContent = "window.log.push('no error script executed');";
+
+ // This should queue a task to run the script, but not run it immediately.
+ document.head.append(noErrorScript);
+
+ log.push("after inserting noErrorScript");
+ assert_array_equals(window.log, [
+ "before any script execution",
+ "after inserting noErrorScript"
+ ]);
+
+ const parseErrorScript = document.createElement("script");
+ parseErrorScript.type = "module";
+ parseErrorScript.async = true;
+ parseErrorScript.textContent = "+++++";
+
+ // This should queue a task to fire the error event, but not fire it immediately.
+ document.head.append(parseErrorScript);
+
+ log.push("after inserting parseErrorScript");
+ assert_array_equals(window.log, [
+ "before any script execution",
+ "after inserting noErrorScript",
+ "after inserting parseErrorScript"
+ ]);
+
+ // After a microtask, the script run / error event must not happen.
+ queueMicrotask(t.step_func(() => {
+ assert_array_equals(window.log, [
+ "before any script execution",
+ "after inserting noErrorScript",
+ "after inserting parseErrorScript"
+ ]);
+ }));
+
+ // But it must eventually happen, after a full task.
+ await t.step_wait(() => window.log.length == 5, "5 items must eventually be logged");
+
+ // And when it does the order must be correct.
+ assert_array_equals(window.log, [
+ "before any script execution",
+ "after inserting noErrorScript",
+ "after inserting parseErrorScript",
+ "no error script executed",
+ "error event on Window"
+ ]);
+});
+</script>
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-template-element/WEB_FEATURES.yml b/testing/web-platform/tests/html/semantics/scripting-1/the-template-element/WEB_FEATURES.yml
new file mode 100644
index 0000000000..bd821885c7
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-template-element/WEB_FEATURES.yml
@@ -0,0 +1,3 @@
+features:
+- name: template
+ files: "**"
diff --git a/testing/web-platform/tests/html/semantics/selectors/pseudo-classes/WEB_FEATURES.yml b/testing/web-platform/tests/html/semantics/selectors/pseudo-classes/WEB_FEATURES.yml
new file mode 100644
index 0000000000..055a5fb4a3
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/selectors/pseudo-classes/WEB_FEATURES.yml
@@ -0,0 +1,11 @@
+features:
+- name: autofill
+ files:
+ - autofill.html
+- name: default
+ files:
+ - default.html
+- name: read-write-pseudos
+ files:
+ - readwrite-readonly-type-change.html
+ - readwrite-readonly.html
diff --git a/testing/web-platform/tests/html/syntax/parsing/template/WEB_FEATURES.yml b/testing/web-platform/tests/html/syntax/parsing/template/WEB_FEATURES.yml
new file mode 100644
index 0000000000..bd821885c7
--- /dev/null
+++ b/testing/web-platform/tests/html/syntax/parsing/template/WEB_FEATURES.yml
@@ -0,0 +1,3 @@
+features:
+- name: template
+ files: "**"
diff --git a/testing/web-platform/tests/html/user-activation/WEB_FEATURES.yml b/testing/web-platform/tests/html/user-activation/WEB_FEATURES.yml
new file mode 100644
index 0000000000..4104016b75
--- /dev/null
+++ b/testing/web-platform/tests/html/user-activation/WEB_FEATURES.yml
@@ -0,0 +1,3 @@
+features:
+- name: user-activation
+ files: "**"
diff --git a/testing/web-platform/tests/html/webappapis/structured-clone/WEB_FEATURES.yml b/testing/web-platform/tests/html/webappapis/structured-clone/WEB_FEATURES.yml
new file mode 100644
index 0000000000..423a469bf1
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/structured-clone/WEB_FEATURES.yml
@@ -0,0 +1,3 @@
+features:
+- name: structured-clone
+ files: "**"